对 C++ 语法的两个好奇心

Two curiosities with the C++ grammar

§5.2[expr.post]/1中我们有表达式列表

的定义

expression-list:
     initializer-list

为什么我们需要两个定义?

§8.5[dcl.init]/1中我们有:

braced-init-list:
     { initializer-list, opt }
     { }

为什么我们需要上面的可选 ,

请注意,此代码段编译:

struct A{
    int i;
    float f;
    A(int i, float f) : i(i), f(f) {}
};

int main()
{
    A a = { 1, 2., };
}

可选的尾随逗号使编写可扩展代码变得容易,而无需修改现有行(非常适合源代码控制)。

比如做一个数组:

int x[] = {
    1,
    2,
    3,
};

如果要添加,只需在新行中添加 4,,完全避免修改带有 3, 的行。这不是必需的,但允许它很好。

结尾的逗号是 C 遗留的,我们可以在 C99 rationale:

中看到这一点

K&R allows a trailing comma in an initializer at the end of an initializer-list. The Standard has retained this syntax, since it provides flexibility in adding or deleting members from an initializer list, and simplifies machine generation of such lists.

这也是comp.lang.c++.moderated: Are comma-separated lists ending in a comma legal?中引用的原因:

yes it is legal. and one reason is to make every line syntactically similar to help automatic tools to deal with large initialization lists

我们可以在 Annotated C++ Reference Manual(ARM) 中找到关于不同初始化风格的更详细的背景,它解释了语法,它说了以下关于 [dcl.init] 的重点:

There are clearly too many notations for initializations, but each seems to serve a particular style of use well. The ={initializer_list,opt} notation was inherited from C and serves well for the initialization of data structures and arrays. [...] The =expression notation also comes from C and is most natural for initializing simple variables, especially of arithmetic or pointer type [...] The {expression-list} notation for initialization came from Simula and seems best when one is creating objects of types that do not for the arithmetic mold.