函数重载:空参数列表与参数包
Function overloading: empty parameter list vs parameter pack
template <typename T>
void call(T) { //#1
std::cout << "1" << std::endl;
}
template <typename T, typename...Args>
void call(T, Args...) { //#2
std::cout << "2" << std::endl;
}
当我像这样调用函数时
call(10);
GCC、Clang 和 MSVC 都使用 #1。
但是,标准中的部分排序规则说:
如果对应于 Pi的参数声明是函数参数包,则将其声明符 id的类型与 A 的参数类型列表中的每个剩余参数类型进行比较。每次比较都会推导出由函数参数包扩展的模板参数包中后续位置的模板参数。在部分排序期间,如果 Ai最初是一个函数参数包:
(10.1( 如果 P 不包含对应于 A i 的函数参数类型,则忽略 Ai;
(10.2(否则,如果Pi不是函数参数包,则模板参数推导失败。
当我们从 #2 推导出 #1 时,T, Args...
为 A,T
为 P,P 不包含对应于Args...
的模板参数。Args...
被忽略,因此可以从 #2 成功推导出 #1。
然后从 #1 推导出 #2,T
为 A,T, Args...
为 P,也成功地产生了T = T, Args... = {}
。
因此,根据偏序规则,当调用call(10)
时,编译器应该给出模棱两可的错误,但实际上所有编译器都调用#1,这是为什么呢?
编译器是正确的。#1
比#2
更专业。
部分排序模板参数包的规则在 [temp.deduct.partial]/8 中指定:
使用得到的类型
P
和A
,推导则为 在 [温度扣除类型] 中描述。如果P
是函数参数包, 参数模板的每个剩余参数类型的类型A
与函数的声明符 ID的类型P
进行比较 参数包。每个比较都推导出模板参数 模板参数包中的后续位置由 函数参数包。同样,如果A
从 函数参数包,与剩余的每个参数进行比较 参数模板的类型。如果给定的扣除成功 类型,参数模板中的类型至少被视为 与参数模板中的类型一样专用。
当参数模板#1
且参数模板#2
时,#2
中的声明符 idArgs
(这是一种类型(将与#1
中剩余的每个参数进行比较(没有(。 因此,#2
至少与#1
一样专业。
当#2
参数模板并且参数模板#1
时,#2
中的声明符 idArgs
(这是一种类型(将与#1
中剩余的每个参数进行比较(没有(。 因此,#1
至少和#2
一样专业。
似乎模棱两可,对吧? 现在我们有了决胜局 [temp.deduct.partial]/11:
如果在考虑上述因素后,函数模板
F
至少为 专门用作函数模板G
,反之亦然,如果G
具有F
没有相应参数包的尾随参数包 参数,如果F
没有尾随参数包,则F
比G
更专业.
显然,#1
比#2
更专业.
- 概念中的cv限定符需要表达式参数列表
- 在没有参数列表的情况下使用模板名称"Event"无效,模板问题
- 错误 没有与参数列表匹配的重载函数"getline"实例
- std::vector 没有重载函数的实例与参数列表匹配
- 模板参数列表中的 false 在模板初始化期间计算为什么?
- C++模板/别名 - 模板参数列表中参数 1 处的类型/值不匹配
- 构造函数/函数声明参数列表中的统一初始化
- 模板化检查是否存在带有参数列表的类成员函数?
- 如何将类成员方法的参数列表自动填充写入可变参数?
- 带有整数的变量参数列表
- 转发变量参数列表以模拟 std::thread
- 错误:"模板<类_Tp,类_Dp>类 std::unique_ptr"的模板参数列表中参数 1 的类型/值不匹配
- C++-将具有引用的长参数列表重构为结构
- 缺少别名模板C++参数列表
- C++如果两个模板函数都与参数列表匹配,将调用哪个模板
- "extern"声明以及带有和不带参数列表的类模板实例的后续定义
- 使用显式模板参数列表和 [temp.arg.explicit]/3 的函数调用的演绎失败
- 没有函数模板的实例与我不知道为什么的参数列表匹配
- 我可以使用宏自动构建参数列表吗?
- 类成员函数参数列表是否可以依赖于模板参数?