C++ 不允许显式指定的模板

C++ 不允许显式指定的模板,c++,C++,我希望有一个广泛的模板,它“做任何需要做的事情”,除非我明确指定了案例 具体来说,我重载了操作符(),将其用于多维矩阵的矩阵索引。我还希望允许使用迭代器指定任意数量的索引。理想情况下,我会有以下签名: operator()(size_t); operator()(size_t,size_t); operator()(size_t,size_t,size_t); ... template<class Iterator> operator()(Iterator,Iterator);

我希望有一个广泛的模板,它“做任何需要做的事情”,除非我明确指定了案例

具体来说,我重载了
操作符()
,将其用于多维矩阵的矩阵索引。我还希望允许使用迭代器指定任意数量的索引。理想情况下,我会有以下签名:

operator()(size_t);
operator()(size_t,size_t);
operator()(size_t,size_t,size_t);
...

template<class Iterator> operator()(Iterator,Iterator);
产出:

operator()(Iterator first, Iterator last)
而我希望这个案例能够输出

operator()(size_t i, size_t j)

几乎可以肯定的是,通过重载解析选择模板的原因是,您传递的两个参数实际上不是
size\t
。它们可能是
int
s或其他东西。如果它们真的是
size\t
s,那么我希望您的非模板重载会被选中。清理这些东西应该可以让事情正常进行,但无论如何都很简单

在这种情况下,通常的方法是当传入的参数为
size\u t
时,使用SFINAE排除模板参与重载解析。大致如下(使用C++17):

template>operator()(迭代器,迭代器)
{
// ...
}
这是你的出发点。使用
std::is_same\u v
很有诱惑力,但您很快就会发现,只有当您传递的正好是
size\u t
时,这才有效。如果你不小心的话,
int
很容易滑进去,在这种情况下,它会崩溃。因此,您可能需要使用
std::is\u integral\u v
。希望您不会在任何地方传递浮点值,而是依赖于它们被截断为下一个最接近的整数值。如果你这样做,你将不得不进一步调整

std::is_integral_v
std::enable_if_t
快捷方式仅在C++17中可用(以及
std::void_t
),但如果有必要,可以在早期标准中重新设计这个轮子


您也可以尝试以相反的方向使用SFINAE:只有当
Iterator
解析为
std::Iterator\u traits
可以识别的内容时,才让此模板参与重载解析。最佳方法取决于您特定的课程要求。

0
1
int
,而不是
std::size\u t
。请阅读。旁注:使用
operator()
编制索引是违反直觉的,请使用
operator[]
而不是使用SFINAE作为模板版本,使用
!例如,std::is_integral::value
。@过路人:
operator()
可以接受多个参数,
operator[]
不能。(但仍然可以使用
std::pair
/
std::tuple
作为参数)。@Jarod42 True。但是,我希望避免每次手动输入索引时都必须键入cast。。。我想你对SFINAE的建议正是我所需要的,谢谢!我会弄清楚确切的语法。
std::void\t
是不必要的,实际上,只需使用
要否定IMO,它更清晰,甚至是
std::negation\u v
。此外,如果您更喜欢
std::negation
,我认为必须删除
\u v
。非常感谢,这非常清楚。也谢谢你带领我绕过这个陷阱,我可能会掉进这个陷阱。
operator()(size_t i, size_t j)
template<class Iterator,
         typename=std::enable_if_t<
                  std::negation_v<std::is_integral_v<Iterator>>>> operator()(Iterator,Iterator)
{
   // ...
}