Wal*_*ter 15 c++ overloading language-lawyer variadic-templates c++11
在解决函数模板重载之间的歧义时,会执行部分排序(有关解释,请参见此处).在那个网站上,我们也了解到了这一点
在平局的情况下,如果一个函数模板具有尾随参数包而另一个没有,则具有省略参数的那个被认为比具有空参数包的那个更专业.
现在,我想知道什么是尾随参数包.如果有的话
template<class ...> struct tuple { /* ... */ };
template<class T, class...Ts> void foo(tuple<T,Ts...>);
template<class T, class...Ts> void bar(T, Ts...);
Run Code Online (Sandbox Code Playgroud)
是和哪个不是为什么?还要注意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?
Run Code Online (Sandbox Code Playgroud)
含糊不清,暗示foo没有尾随参数包.
这是CWG1395,最近在C++ 17标准草案中对缺陷解决方案进行了投票.以下内容已添加到[temp.deduct.partial]:
... [if]函数模板
F至少与函数模板一样专用,G反之亦然,如果G有一个尾随参数包,其中F没有相应的参数,如果F没有尾随参数包,则F更多专业比G.
标准没有明确定义"trailing parameter pack"的含义,但是根据使用该术语的现有上下文来判断,它指的是模板参数包,它在模板参数列表中显示为最右边的参数:
template<class T, class... U> struct X;
// ^^^^^^^^^^
Run Code Online (Sandbox Code Playgroud)
或者,函数参数包在函数参数列表中显示为最右边的参数:
template<class T, class... U> void y(T, U...);
// ^^^^
Run Code Online (Sandbox Code Playgroud)
当前草案仍包含[temp.deduct.type]中的过时示例:
template<class T, class... U> void f(T, U...);
template<class T> void f(T);
f(&i); // error: ambiguous
Run Code Online (Sandbox Code Playgroud)
这份标准缺陷报告已经存在了几年,GCC和Clang都已经实施了它的决议.他们都同意上面的例子是第二次重载的有效调用f.
GCC和Clang不同意的是缺陷解决方案的范围.这是可以理解的,因为它最近才更新,以包括拟议的标准措辞.在您的示例中,包不会扩展到函数参数列表中,而是扩展到函数参数类型的模板参数列表中:
template<class T, class... U> void g(tuple<T, U...>);
template<class T> void g(tuple<T>);
g(tuple<int>{});
Run Code Online (Sandbox Code Playgroud)
GCC将此视为第二次超载的有效调用g; Clang认为它含糊不清.Clang的正确性可能取决于"尾随参数包"是否包含尾随模板参数包,或仅包含尾随函数参数包.
请注意,两个编译器都同意在下面的示例中C<int>引用类模板的第二个部分特化C:
template<class...> struct C;
template<class T, class... U> struct C<T, U...> {};
template<class T> struct C<T> {};
Run Code Online (Sandbox Code Playgroud)
这似乎是Clang中的不一致,因为类模板特化的部分排序的标准规则是根据函数模板的部分排序来定义的.见CWG1432.