也许我不是来自这个星球,但在我看来,以下应该是一个语法错误:
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.
那么,有什么特别的原因,这个多余的逗号是明确允许的吗?
它使得生成数组或枚举的代码生成器更容易。
想象一下:
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("}")
像许多东西一样,数组初始化器中的尾随逗号是c++从C继承的东西之一(并且必须永远支持)。在《Deep C secrets》一书中提到了与此完全不同的观点。
在一个有多个“逗号悖论”的例子之后:
char *available_resources[] = {
"color monitor" ,
"big disk" ,
"Cray" /* whoa! no comma! */
"on-line drawing routines",
"mouse" ,
"keyboard" ,
"power cables" , /* and what's this extra comma? */
};
我们读到:
...最后一个初始化式后面的逗号不是一个拼写错误,而是从原始c中继承下来的语法中的一个小点。它的存在或不存在是允许的,但没有任何意义。在ANSI C基本原理中声称的理由是,它使C的自动生成更容易。如果允许在每个以逗号分隔的列表中使用尾随逗号,例如在枚举声明中,或在单个声明中使用多个变量声明器,则声明将更加可信。事实并非如此。
... 对我来说,这更有意义
它使生成代码更容易,因为您只需要添加一行,而不需要将添加最后一个条目视为特殊情况。在使用宏生成代码时尤其如此。有一种努力试图从语言中消除对宏的需求,但许多语言确实是与可用的宏一起发展的。额外的逗号允许定义和使用以下宏:
#define LIST_BEGIN int a[] = {
#define LIST_ENTRY(x) x,
#define LIST_END };
用法:
LIST_BEGIN
LIST_ENTRY(1)
LIST_ENTRY(2)
LIST_END
这是一个非常简单的示例,但宏通常使用此模式来定义分派、消息、事件或转换映射和表等内容。如果结尾不允许用逗号,我们需要一个特殊的:
#define LIST_LAST_ENTRY(x) x
用起来会很尴尬。