也许我不是来自这个星球,但在我看来,以下应该是一个语法错误:

int a[] = {1,2,}; //extra comma in the end

但事实并非如此。当这段代码在Visual Studio上编译时,我很惊讶,但我已经学会了不相信MSVC编译器,就c++规则而言,所以我检查了标准,它也是标准允许的。如果你不相信的话,语法规则可以参考8.5.1。

Why is this allowed? This may be a stupid useless question but I want you to understand why I am asking. If it were a sub-case of a general grammar rule, I would understand - they decided not to make the general grammar any more difficult just to disallow a redundant comma at the end of an initializer list. But no, the additional comma is explicitly allowed. For example, it isn't allowed to have a redundant comma in the end of a function-call argument list (when the function takes ...), which is normal.

那么,有什么特别的原因,这个多余的逗号是明确允许的吗?


当前回答

我认为是为了便于开发人员使用。

int a[] = {
            1,
            2,
            2,
            2,
            2,
            2, /*line I could comment out easily without having to remove the previous comma*/
          }

此外,如果出于某种原因,你有一个为你生成代码的工具;该工具不需要关心它是否是初始化中的最后一项。

其他回答

据我所知,允许这样做的原因之一是自动生成代码应该很简单;最后一个元素不需要任何特殊处理。

我看到了一个在其他答案中没有提到的用例, 我们最喜欢的宏:

int a [] = {
#ifdef A
    1, //this can be last if B and C is undefined
#endif
#ifdef B
    2,
#endif
#ifdef C
    3,
#endif
};

添加宏到最后处理,将是巨大的痛苦。通过语法上的这个小变化,管理起来很简单。这比机器生成的代码更重要因为用图灵完备语言比用有限的预处理器要容易得多。

我很惊讶这么长时间以来没有人引用注解c++参考手册(ARM),它是这样描述[dcl. C]的。我的:

用于初始化的表示法显然太多了,但每种表示法似乎都适用于特定的使用风格。={initializer_list,opt}符号继承自C语言,可以很好地初始化数据结构和数组。[…]

尽管自ARM诞生以来语法一直在发展,但起源仍然存在。

我们可以查看C99的基本原理,看看为什么在C中允许这样做,它说:

类的初始化式中允许有一个尾随逗号 初始化器列表。标准保留了这个语法,因为它 提供从初始化式中添加或删除成员的灵活性 列表,并简化了此类列表的机器生成。

它使得生成数组或枚举的代码生成器更容易。

想象一下:

std::cout << "enum Items {\n";
for(Items::iterator i(items.begin()), j(items.end); i != j; ++i)
    std::cout << *i << ",\n";
std::cout << "};\n";

也就是说,不需要对第一项或最后一项进行特殊处理,以避免出现尾随逗号。

例如,如果代码生成器是用Python编写的,使用str.join()函数可以很容易地避免吐出尾随逗号:

print("enum Items {")
print(",\n".join(items))
print("}")

它允许每一行都遵循相同的形式。首先,这样可以更容易地添加新行,并让版本控制系统有效地跟踪更改,还可以更容易地分析代码。我想不出技术上的原因。