C++ int a[] = {1,2,}; 允许奇怪的逗号。有什么特别的原因吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7043372/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 16:24:04  来源:igfitidea点击:

int a[] = {1,2,}; Weird comma allowed. Any particular reason?

c++syntaxgrammarlanguage-lawyer

提问by Armen Tsirunyan

Maybe I am not from this planet, but it would seem to me that the following should be a syntax error:

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

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

But it's not. I was surprised when this code compiled on Visual Studio, but I have learnt not to trust MSVC compiler as far as C++ rules are concerned, so I checked the standard and it isallowed by the standard as well. You can see 8.5.1 for the grammar rules if you don't believe me.

但事实并非如此。当在Visual Studio中编译的代码我很惊讶,但我已经学会了不信任MSVC编译器尽可能C ++的规则而言,所以我检查的标准,它标准允许为好。如果你不相信我,你可以看到 8.5.1 的语法规则。

enter image description here

在此处输入图片说明

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 explicitlyallowed. 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.

为什么这是允许的?这可能是一个愚蠢无用的问题,但我想让你明白我为什么要问。如果它是一般语法规则的一个子案例,我会理解 - 他们决定不让一般语法变得更加困难,只是为了禁止在初始化列表末尾使用多余的逗号。但是不,明确允许额外的逗号。例如,在函数调用参数列表的末尾(当函数采用 时...)不允许有多余的逗号,这是正常的

So, again, is there any particular reason this redundant comma is explicitlyallowed?

那么,再一次,明确允许使用这个多余的逗号是否有任何特殊原因?

回答by Jon Skeet

It makes it easier to generate source code, and also to write code which can be easily extended at a later date. Consider what's required to add an extra entry to:

它使生成源代码和编写可以在以后轻松扩展的代码变得更加容易。考虑添加额外条目需要什么:

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

... you have to add the comma to the existing line andadd a new line. Compare that with the case where the three alreadyhas a comma after it, where you just have to add a line. Likewise if you want to remove a line you can do so without worrying about whether it's the last line or not, and you can reorder lines without fiddling about with commas. Basically it means there's a uniformity in how you treat the lines.

...您必须将逗号添加到现有行添加新行。将其与三个后面已经有逗号的情况进行比较,您只需添加一行。同样,如果您想删除一行,您可以这样做而不必担心它是否是最后一行,并且您可以重新排列行而无需摆弄逗号。基本上,这意味着您处理线条的方式是一致的。

Now think about generating code. Something like (pseudo-code):

现在考虑生成代码。类似(伪代码):

output("int a[] = {");
for (int i = 0; i < items.length; i++) {
    output("%s, ", items[i]);
}
output("};");

No need to worry about whether the current item you're writing out is the first or the last. Much simpler.

无需担心您正在写出的当前项目是第一个还是最后一个。简单多了。

回答by Skilldrick

It's useful if you do something like this:

如果您执行以下操作,这很有用:

int a[] = {
  1,
  2,
  3, //You can delete this line and it's still valid
};

回答by vcsjones

Ease of use for the developer, I would think.

我认为易于开发人员使用。

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

Additionally, if for whatever reason you had a tool that generated code for you; the tool doesn't have to care about whether it's the last item in the initialize or not.

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

回答by Oliver Charlesworth

I've always assumed it makes it easier to append extra elements:

我一直认为添加额外元素更容易:

int a[] = {
            5,
            6,
          };

simply becomes:

简单地变成:

int a[] = { 
            5,
            6,
            7,
          };

at a later date.

在以后的日子。

回答by amoss

Everything everyone is saying about the ease of adding/removing/generating lines is correct, but the real place this syntax shines is when merging source files together. Imagine you've got this array:

每个人都说的添加/删除/生成行的简便性是正确的,但这种语法的真正亮点在于将源文件合并在一起时。想象一下你有这个数组:

int ints[] = {
    3,
    9
};

And assume you've checked this code into a repository.

并假设您已将此代码签入存储库。

Then your buddy edits it, adding to the end:

然后你的好友编辑它,添加到最后:

int ints[] = {
    3,
    9,
    12
};

And you simultaneously edit it, adding to the beginning:

你同时编辑它,添加到开头:

int ints[] = {
    1,
    3,
    9
};

Semantically these sorts of operations (adding to the beginning, adding to the end) should be entirely merge safe and your versioning software (hopefully git) should be able to automerge. Sadly, this isn't the case because your version has no comma after the 9 and your buddy's does. Whereas, if the original version had the trailing 9, they would have automerged.

从语义上讲,这些类型的操作(添加到开头,添加到结尾)应该是完全合并安全的,并且您的版本控制软件(希望是 git)应该能够自动合并。可悲的是,情况并非如此,因为您的版本在 9 之后没有逗号,而您的好友则有。然而,如果原始版本有尾随 9,它们就会自动合并。

So, my rule of thumb is: use the trailing comma if the list spans multiple lines, don't use it if the list is on a single line.

所以,我的经验法则是:如果列表跨越多行,则使用尾随逗号,如果列表位于单行上,则不要使用它。

回答by Gene Bushuyev

Trailing comma I believe is allowed for backward compatibility reasons. There is a lot of existing code, primarily auto-generated, which puts a trailing comma. It makes it easier to write a loop without special condition at the end. e.g.

出于向后兼容性的原因,我认为允许使用尾随逗号。有很多现有的代码,主要是自动生成的,它们会在尾部添加一个逗号。这使得在末尾没有特殊条件的情况下更容易编写循环。例如

for_each(my_inits.begin(), my_inits.end(),
[](const std::string& value) { std::cout << value << ",\n"; });

There isn't really any advantage for the programmer.

程序员真的没有任何优势。

P.S. Though it is easier to autogenerate the code this way, I actually always took care not to put the trailing comma, the efforts are minimal, readability is improved, and that's more important. You write code once, you read it many times.

PS 虽然这样自动生成代码更容易,但我实际上总是注意不要放尾随逗号,努力很小,可读性提高,这更重要。你写一次代码,你读了很多次。

回答by Fredrik Pihl

One of the reasons this is allowed as far as I know is that it should be simple to automatically generate code; you don't need any special handling for the last element.

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

回答by Maxim Egorushkin

It makes code generators that spit out arrays or enumerations easier.

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

Imagine:

想象:

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

I.e., no need to do special handling of the first or last item to avoid spitting the trailing comma.

即,无需对第一项或最后一项进行特殊处理以避免吐出尾随逗号。

If the code generator is written in Python, for example, it is easy to avoid spitting the trailing comma by using str.join()function:

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

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

回答by Shafik Yaghmour

I am surprised after all this time no one has quoted the Annotated C++ Reference Manual(ARM), it says the following about [dcl.init]with emphasis mine:

我很惊讶这么长时间以来没有人引用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 Cand serves well for the initialization of data structures and arrays. [...]

显然有太多的初始化符号,但每个符号似乎都能很好地服务于特定的使用风格。= {initializer_list,选择}符号被选自C继承和用于数据结构和数组的初始化提供良好服务。[...]

although the grammar has evolved since ARMwas written the origin remains.

尽管自编写ARM以来语法已经发展,但起源仍然存在。

and we can go to the C99 rationaleto see why this was allowed in C and it says:

我们可以转到C99 的基本原理来了解为什么在 C 中允许这样做,它说:

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.

K&R 允许在初始值设定项列表末尾的初始值设定项中使用尾随逗号。标准保留了这种语法,因为它 提供了在初始化列表中添加或删除成员的灵活性,并简化了此类列表的机器生成。

回答by Yankes

I see one use case that was not mentioned in other answers, our favorite Macros:

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

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

Adding macros to handle last ,would be big pain. With this small change in syntax this is trivial to manage. And this is more important than machine generated code because is usually lot of easier to do it in Turing complete langue than very limited preprocesor.

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