[英]Function template argument deduction with variadic class template as function call parameter
All the examples are from here and here . 所有的例子都在这里和这里 。
Specifically, 特别,
template<class...> struct Tuple { };
template< class... Types> void g(Tuple<Types ...>); // #1
// template<class T1, class... Types> void g(Tuple<T1, Types ...>); // #2
template<class T1, class... Types> void g(Tuple<T1, Types& ...>); // #3
g(Tuple<>()); // calls #1
g(Tuple<int, float>()); // calls #2
g(Tuple<int, float&>()); // calls #3
g(Tuple<int>()); // calls #3
With #2
uncommented, g()'s are resolved as described in the comments. 如果没有注释#2
,则按照注释中的描述解析g()。 What surprises me is that if I comment out the #2
line, the g()'s calls are resolved as follows: 令我惊讶的是,如果我注释掉#2
行,则g()的调用将按以下方式解决:
g(Tuple<>()); // calls #1
g(Tuple<int, float>()); // calls **#1 ???? why not #3????**
g(Tuple<int, float&>()); // calls #3
g(Tuple<int>()); // calls #3
From the following examples and explanations below I can't see why g(Tuple<int, float>());
从下面的以下示例和说明中,我看不到为什么g(Tuple<int, float>());
can't resolved to #3
. 无法解析为#3
。 It is the direction application of the following two rules: 它是以下两个规则的定向应用:
If a parameter pack appears as the last P, then the type P is matched against the type A of each remaining argument of the call. 如果参数包显示为最后一个P,则将类型P与调用的每个其余自变量的类型A匹配。 Each match deduces the template arguments for the next position in the pack expansion. 每次匹配都会推导出包扩展中下一个位置的模板参数。
template<class ... Types> void f(Types& ...);
void h(int x, float& y) {
const int z = x;
f(x, y, z); // P=Types&..., A1=x: deduces the first member of Types... to int
// P=Types&..., A2=y: deduces the second member of Types... to float
// P=Types&..., A3=z: deduces the third member of Types... to const int
// calls f<int, float, const int>
If P has one of the forms that include a template parameter list
<T>
or<I>
, then each element Pi of that template argument list is matched against the corresponding template argument Ai of its A. If the last Pi is a pack expansion, then its pattern is compared against each remaining argument in the template argument list of A. A trailing parameter pack that is not otherwise deduced, is deduced to an empty parameter pack. 如果P具有包含模板参数列表<T>
或<I>
的形式之一,则该模板参数列表的每个元素Pi与其A的对应模板参数Ai匹配。如果最后一个Pi是一个包扩展,然后将其模式与A的模板参数列表中的每个其余参数进行比较。否则将未推导的尾随参数包推导为空参数包。
There's a misconception here between your two examples. 您的两个示例之间存在误解。 In the 2nd example with f
, you are deducing reference arguments to a function. 在带有f
的第二个示例中,您将推导函数的引用参数 。 In the 1st example with g
, you are deducing reference template parameters to an argument to a function. 在带有g
的第一个示例中,您将引用模板参数推导为函数的参数。 The latter must match exactly, but the former is deduced against the referred types. 后者必须完全匹配,但是前者是根据引用的类型推导出来的。 They are not the same. 她们不一样。
In your fist example, 在你的拳头例子中
g(Tuple<int, float>());
cannot call g(Tuple<T1, Types&...>)
. 无法调用g(Tuple<T1, Types&...>)
。 The template deduction process is about picking a deduced argument type that is identical to the called argument type. 模板推导过程是关于选择一个与被调用参数类型相同的推导参数类型。 There are some exceptions (for referenced cv-qualifications, pointers, derived classes, arrays, functions), but none of those apply here. 有一些例外(对于引用的cv限定词,指针,派生类,数组,函数),但均不适用。 We simply need to pick T1
and Types...
such that Tuple<T1, Types&...>
is the same type as Tuple<int, float>
. 我们只需要选择T1
和Types...
,以使Tuple<T1, Types&...>
与Tuple<int, float>
是相同的类型。 This is impossible as there is no such pack Types...
for which Types&...
is {float}
, since float
is not a reference! 这是不可能的,因为不存在Types&...
为{float}
包Types...
,因为float
不是引用!
So once you comment out (2), there's only one viable candidate: (1). 因此,一旦您注释掉(2),就只有一个可行的候选人:(1)。
On the other hand, 另一方面,
template<class ... Types> void f(Types& ...);
void h(int x, float& y) {
const int z = x;
f(x, y, z);
}
Here, Types&...
is actually the type of the parameter itself (rather than a template argument of it), so (temp.deduct.call): 在这里, Types&...
实际上是参数本身的类型(而不是它的模板参数),因此(temp.deduct.call):
If P is a reference type, the type referred to by P is used for type deduction. 如果P是引用类型,则将P引用的类型用于类型推导。
We deduce Types...
to match the arguments. 我们推导Types...
以匹配参数。 This succeeds because all the arguments are lvalues, and we simply pick {int, float, const int}
. 之所以成功,是因为所有参数都是左值,我们只需选择{int, float, const int}
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.