究竟什么是"trailing parameter pack"

What exactly is a "trailing parameter pack"

本文关键字:parameter pack trailing 究竟 什么      更新时间:2023-10-16

在解决函数模板重载之间的歧义时,执行部分排序(有关一些解释,请参阅此处)。在该网站中,我们还了解到

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

现在,我想知道尾随参数包到底是什么。其中如果有的话

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没有尾随参数包。

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

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

该标准没有明确定义"尾随参数包"的含义,但从使用该术语的现有上下文来看,它指的是在模板参数列表中显示为最右侧参数的模板参数包:

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

这个标准缺陷报告已经存在了几年,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>{});

GCC 将此视为g的第二次重载的有效调用;叮当,淳言不暧。Clang的正确性可能取决于"尾随参数包"是旨在包含尾随模板参数包,还是仅包含尾随函数参数包。

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

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

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

尾随的意思是"在末尾"。

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

template <typename T1, typename... Ts>
void foo();
// ^ Ts... is trailing here

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