【发布时间】:2022-01-05 13:16:02
【问题描述】:
我有:
template<typename ...Ts, typename U, typename=void>
void valid(Ts..., U){}
int main() {
valid(1.0, 1, 2, 3);
}
clang 抱怨:
note: candidate function [with Ts = <>, U = double, $2 = void] not viable: requires 1 argument, but 4 were provided
void valid(Ts..., U){}
^
而 gcc 抱怨:
<source>:2:6: note: template argument deduction/substitution failed:
<source>:5:10: note: candidate expects 1 argument, 4 provided
5 | valid(1.0, 1, 2, 3);
| ~~~~~^~~~~~~~~~~~~~
根据 cling,编译器似乎推断出 Tn 是一个空包(即 )。这是为什么?我认为给定参数列表 (1.0, 1, 2, 3),U 将推导出为 int 和 Tn... 将是 double, int, int。这里类型推导的规则是什么?
如果我将调用者更改为:
valid<double, int, int>(1.0, 1, 2, 3);
它有效。但是,如果我将其更改为:
valid<double, int, int, int>(1.0, 1, 2, 3);
失败了:
<source>:2:6: note: template argument deduction/substitution failed:
<source>:5:33: note: candidate expects 5 arguments, 4 provided
5 | valid<double, int, int, int>(1.0, 1, 2, 3);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~
这里使用什么规则来确定我可以在类型参数列表中指定哪些类型?
谢谢。
【问题讨论】:
-
Ts...是非扣除上下文,因此模板参数扣除永远不会为它工作。尚不确定为什么明确指定的参数不起作用。 "[temp.deduct.type]/5 非推导上下文是: ... (5.7) — 一个函数参数包,不会出现在参数声明列表。” -
啊。 "[temp.deduct.type]/9 ...如果Pi是包展开,则Pi的模式与A 的模板参数列表中的每个剩余参数。每个比较推导出模板参数包中由 Pi 扩展的后续位置的模板参数。”强调我的。换句话说,一旦您开始匹配参数包,所有后续参数都被假定属于该参数包。所以在
valid<double, int, int, int>(1.0, 1, 2, 3)调用中,Ts...被取为四种类型{double, int, int, int},然后实例化需要5个参数。