去年,我在“What does the …… mean in C++?”一文中专门介绍过 ...... 这种极其罕见的 C++ 语法,它其实是 ..., ... 的省略语法。以下这三种写法完全等价:

template<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(省略符参数),容易造成困惑和误用。

弃用后,语法规则变为:

parameter-declaration-clause:
    parameter-declaration-listoptopt
    …
    parameter-declaration-listopt
    parameter-declaration-list , …

于是,以 int...(泛指)作为 int, ... 等价用法的行为全部变得非法。例如:

void 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

还有下面这两个语法相近却意义不同的例子:

// 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:

// OK, ellipsis parameters, compatible with C
void f(...);
void g(int, ...);

Leave a Reply

Your email address will not be published. Required fields are marked *

You can use the Markdown in the comment form.