请考虑以下代码:
#include <iostream>
#include <type_traits>
// Variadic version
template<class... Variadic>
void f(const Variadic&... variadic)
{
std::cout<<"variadic"<<std::endl;
}
// Single version
template<class Single, class = typename std::enable_if<std::is_fundamental<Single>::value>::type>
void f(const Single& single)
{
std::cout<<"single"<<std::endl;
}
// Main
int main()
{
f(); // variadic
f(42); // single : why?
f(std::string()); // variadic
f(42, 42); // variadic
return 0;
}
我不明白为什么标记为“single”的行编译得很好(在g ++ 4.6.3下)并且不会产生重载解析问题。 c ++ 11标准是否说具有固定数量参数的模板函数优先于可能具有相同签名的可变参数函数?
答案 0 :(得分:5)
It is really quite simple(两个实例,gcc和clang)
template<class...T> void foo(T&&...) {std::cout << "...T\n";}
template<class T> void foo(T&&) {std::cout << "T\n";}
int main() {
foo(3);
}
如果选择是显式模板参数,则不会将...
视为首选的重载。
class=std::enable_if_t
不会改变这一点。
因此,你的函数f
都是候选函数,然后编译器更喜欢没有变量函数的函数。
/ 8:
如果从函数参数包转换
A
并且P
不是参数包,则类型推导失败。否则,使用生成的类型P
和A
,然后按14.8.2.5
中所述完成扣除。如果P
是函数参数包,则将参数模板的每个剩余参数类型的类型A
与声明者标识的类型P进行比较 功能参数包的。每个比较都推导出函数参数包扩展的模板参数包中后续位置的模板参数。如果对于给定类型的推导成功,则参数模板中的类型被认为至少与参数模板中的类型一样专用。 [ 例如:
template<class... Args> void f(Args... args); // #1
template<class T1, class... Args> void f(T1 a1, Args... args); // #2
template<class T1, class T2> void f(T1 a1, T2 a2); // #3
f(); // calls #1
f(1, 2, 3); // calls #2
f(1, 2); // calls #3; non-variadic template #3 is more
// specialized than the variadic templates #1 and #
特别是f(1,2)
示例。
当您将enable_if_t
作为std::string
传递时,所有T
子句都会删除单参数版本。
答案 1 :(得分:2)
由于在'single'版本中使用了第二个enable_if,template参数,编译器认为该版本是一个更专用的模板,用于与其启用的类型一起使用。
它被认为更专业,因为有些类型可以实例化可变参数模板,但“单一”不能。
一般规则是,更专业的模板在过载解析中胜过不太专业的模板。