究竟什么是“尾随参数包”

时间:2016-12-09 14:11:47

标签: c++ c++11 language-lawyer variadic-templates overloading

在解决函数模板重载之间的歧义时,会执行部分排序(有关解释,请参阅here)。在那个网站上,我们也了解到了

  

如果一个平局,如果一个函数模板有一个尾随参数   pack和另一个没有,带有省略参数的那个是   被认为比空的更专业   参数包。

现在,我想知道尾随参数包究竟是什么。如果有的话

template<class ...> struct tuple { /* ... */ };

template<class T, class...Ts> void foo(tuple<T,Ts...>);

template<class T, class...Ts> void bar(T, Ts...);

是哪个不是为什么?另请注意,clang认为

template<class T> void f(tuple<T>);

template<class T, class...Ts> void f(tuple<T,Ts...>);

int main()
{  f(tuple<int>());  }   // ambiguous call?

含糊不清,暗示foo没有尾随参数包。

2 个答案:

答案 0 :(得分:7)

这是CWG1395,最近在C ++ 17标准草案中投了缺陷resolution。以下内容已添加到[temp.deduct.partial]:

  

... [if]函数模板F至少与函数模板G一样专用,反之亦然,如果G有一个尾随参数包F 1}}没有相应的参数,如果F没有尾随参数包,则FG更专业。

标准没有明确定义&#34;尾随参数包&#34;的含义,但是根据使用该术语的现有上下文来判断,它指的是一个模板参数包,它显示为模板参数列表中最右边的参数:

template<class T, class... U> struct X;
//                ^^^^^^^^^^

或者,函数参数包在函数参数列表中显示为最右边的参数:

template<class T, class... U> void y(T, U...);
//                                      ^^^^

当前草稿仍然包含[temp.deduct.type]中的过时示例:

template<class T, class... U> void f(T, U...);
template<class T> void f(T);

f(&i); // error: ambiguous

此标准缺陷报告已存在几年,GCCClang已实施其解决方案。他们都同意上面的例子是对f的第二次重载的有效调用。

GCC和Clang不同意缺陷解决方案的范围。这是可以理解的,因为它最近才更新,以包括拟议的标准措辞。在您的示例中,包不会扩展到函数参数列表中,而是扩展到函数参数类型的模板参数列表中:

template<class T, class... U> void g(tuple<T, U...>);
template<class T> void g(tuple<T>);

g(tuple<int>{});

GCC将此视为g第二次重载的有效调用; Clang认为它含糊不清。 Clang的正确性可能取决于&#34;尾随参数包&#34;旨在包含尾随模板参数包,或仅包含尾随功能参数包。

请注意,两个编译器都同意C<int>引用以下示例中类模板C的第二个部分特化:

template<class...> struct C;

template<class T, class... U> struct C<T, U...> {};
template<class T> struct C<T> {};

这似乎是Clang中的不一致,因为类模板特化的部分排序的标准规则是根据函数模板的部分排序来定义的。请参阅CWG1432

答案 1 :(得分:0)

Trailing表示&#34;在#34;

结束时

尾随参数包是在模板参数列表末尾找到的参数包:

template <typename T1, typename... Ts>
void foo();

// ^ Ts... is trailing here

这不是C ++问题,而是英语问题。