…… 这种极其罕见的 C++ 语法,它其实是 …, … 的省略语法。
以下这三种写法其实完全等价:1
2
3template<class... Args> void f(Args......) {}
template<class... Args> void f(Args... ...) {}
template<class... Args> void f(Args..., ...) {}
第一个 ... 用于扩展 C++ 可变模板参数包,而第二个 ... 用于匹配 C 语言中 Variadic functions 的旧式变参。
完整的用法及实例在原文中已经详细讲述,没有读过的可以移步阅读。
到了 C++26,前两种写法被弃用,逗号不再可以省略。原因主要有两点:一是会对未来任何试图使用 int... 这种语法的提案产生影响;二是许多用户把 int... 理解为一个模板参数包,而非 Ellipsis Parameters(省略符参数),容易造成困惑和误用。
弃用后,语法规则变为:1
2
3
4parameter-declaration-clause:
...
parameter-declaration-listopt
parameter-declaration-list , ...
于是,以 int...(泛指)作为 int, ... 等价用法的行为全部变得非法。例如:1
2
3
4
5void f(int...); // deprecated
void f(int x...); // deprecated
void g(auto...); // OK, declares a function parameter pack
void h(auto......); // deprecated
template<class... Ts> void a(Ts...); // OK, function template parameter pack
还有下面这两个语法相近却意义不同的例子:1
2
3
4// abbreviated variadic function template
void g(auto ...args);
// abbreviated non-variadic function template with ellipsis parameter
void g(auto args...);
第二个用法如今已被弃用。
顺便提一下,之前 T... 既可以被解释为模板参数包,也可以被解释为 T 紧跟着一个 Ellipsis Parameter。之所以未曾出现歧义,是因为编译器会优先将其解释为模板参数包。如今只剩下第一种解释,完全不会出现歧义。
说明符 ... 依旧是合法的,与 C 中的行为保持兼容。简言之,下面这两种写法仍然表示 Ellipsis Parameters:1
2
3// OK, ellipsis parameters, compatible with C
void f(...);
void g(int, ...);