可变参数列表vs单一模板参数:标准怎么说?
variadic list vs single template parameter: what does the standard say?
考虑以下代码:
#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标准是否规定具有固定数量形参的模板函数优于具有相同签名的可变函数?
这真的很简单(两个实例,gcc和clang)
template<class...T> void foo(T&&...) {std::cout << "...Tn";}
template<class T> void foo(T&&) {std::cout << "Tn";}
int main() {
foo(3);
}
当选择显式模板参数时,不使用...
的重载似乎更受欢迎。
class=std::enable_if_t
不改变这个
所以你的两个函数f
都是候选函数,那么编译器更喜欢没有变量的函数。
14.8.2.4在部分排序时推导模板参数[temp.演绎.partial]
/8:
如果
A
是从函数参数包转换而P
不是参数包,则类型推导失败。否则,使用结果类型P
和A
,然后按照14.8.2.5
的描述进行演绎。如果P
是一个函数形参包,则实参模板的每个剩余形参类型的A
类型将与声明器id的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
传递时,从考虑中删除单参数版本。
由于在'single'版本中使用了第二个模板参数enable_if,编译器认为该版本是一个更专门化的模板,可以与它所启用的类型一起使用。
它被认为是更专门化的,因为在某些类型中可变模板可以被实例化,但'single'不能。
一般规则是,在重载解析方面,专门化程度高的模板优于专门化程度低的模板。
相关文章:
- 标准::向量声明中使用的模板参数
- 如何使用模板化标准::函数作为参数?
- 标准::enable_if 和标准::is_arithmetic 作为模板参数的问题
- 多维标准::数组的可变参数模板
- 在标准中,模板参数的语法在哪里定义,例如,'std::function<int(char)>'?
- 标准对此指向成员函数类型模板参数有何说明?是我的代码有误,还是 MSVS 16.6 有问题?
- 参数归纳与标准::变体
- 可变参数模板和标准::函数
- 从常量字符*、字符*参数到标准::字符串的直接转换接口
- 标准::原子::compare_exchange与两个memory_order参数一起使用的真实示例
- 标准是否阻止在可变参数模板中使用足够小的文本值缩小文本转换范围
- 标准::basic_ostream参数
- 删除 Netbeans 中的标准运行参数
- C++11:标准::result_of<>模板参数与标准::函数<>
- 为什么 C++17 标准没有带来部分类模板参数扣除?
- 依赖的非类型参数包:标准怎么说?
- 为什么使用标准类型作为模板参数?
- 为什么C++标准中没有 std::basic_string 类的构造函数,其参数类型为 std::string_view
- C++标准是否保证失败的插入到关联容器中不会修改 rvalue-reference 参数?
- 可变参数列表vs单一模板参数:标准怎么说?