函数模板参数推导与可变参数类模板作为函数调用参数

时间:2015-10-29 23:19:40

标签: c++ templates overload-resolution

所有示例均来自herehere

具体地,

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

如果取消注释#2,则会按照评论中的说明解析g()&。让我感到惊讶的是,如果我注释掉#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

通过以下示例和说明,我无法理解为什么g(Tuple<int, float>());无法解析为#3。它是以下两条规则的方向应用:

  

如果参数包显示为最后一个P,则类型P与呼叫的每个剩余参数的类型A匹配。每个匹配都会推断包扩展中下一个位置的模板参数。

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>
  

如果P具有包含模板参数列表<T><I>的表单之一,则该模板参数列表的每个元素Pi与其A的对应模板参数Ai匹配。最后一个Pi是一个包扩展,然后将它的模式与A的模板参数列表中的每个剩余参数进行比较。一个未被推导出的尾随参数包,推断为空参数包。

1 个答案:

答案 0 :(得分:2)

你的两个例子之间存在误解。在使用f的第二个示例中,您将向函数推断引用参数。在带有g的第一个示例中,您将参考模板参数推断为函数的参数。后者必须完全匹配,但前者是根据引用的类型推断出来的。它们不一样。

在你的第一个例子中,

g(Tuple<int, float>());

无法致电g(Tuple<T1, Types&...>)。模板推导过程是关于选择与被调参数类型相同的推导出的参数类型。有一些例外(对于引用的cv资格,指针,派生类,数组,函数),但这些都不适用于此。我们只需选择T1Types...Tuple<T1, Types&...>Tuple<int, float>的类型相同。这是不可能的,因为Types... Types&...不是{float},因为float不是参考!

所以一旦你评论出(2),只有一个可行的候选人:(1)。

另一方面,

template<class ... Types> void f(Types& ...);
void h(int x, float& y) {
    const int z = x;
    f(x, y, z);
}

这里,Types&...实际上是参数本身的类型(而不是它的模板参数),所以(temp.deduct.call):

  

如果P是引用类型,则P引用的类型用于类型推导。

我们推导出Types...以匹配参数。这是成功的,因为所有参数都是左值,我们只需选择{int, float, const int}