12

In §5.2[expr.post]/1 we have the definition of expression-list

expression-list:
     initializer-list

Why do we need both definitions?

In §8.5[dcl.init]/1 we have:

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

Why do we need the optional , above?

Note that this snippet compiles:

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

int main()
{
    A a = { 1, 2., };
}
Belloc
  • 6,318
  • 3
  • 22
  • 52
  • The second question has already been answered elsewhere (by Jon Skeet himself IIRC) – Columbo Oct 18 '15 at 16:53
  • 4
    Elsewhere being [here](http://stackoverflow.com/questions/7043372/int-a-1-2-weird-comma-allowed-any-particular-reason) – chris Oct 18 '15 at 16:53
  • 5
    The traling commas in braced-init lists come from C, and they're useful when you a) generate the list with something b) when you have the list spread across multiple lines and you want to add an item or sort the list. The uniformity helps in making the editing task easier. – Petr Skocik Oct 18 '15 at 16:55
  • @chris Thanks for the link – Belloc Oct 18 '15 at 17:13
  • 1
    First one probably is for historical reasons. In C++03 *expression-list* is really a comma-separated list of *assignment-expression*s. Then in C++11, they wanted to allow braced initializers to be used too, and it's presumably simpler and less error-prone to change the production of *expression-list* than to do surgeries across the standard. – T.C. Oct 18 '15 at 20:57
  • @T.C. I agree, that's a good explanation. Thanks. – Belloc Oct 18 '15 at 22:51

2 Answers2

18

The optional trailing comma makes it easy to write code that is extendable without modifying existing lines (nice for source control).

For example, making an array:

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

If you want to add to it, you just add 4, on a new line, and avoid modifying the line with the 3, at all. It's not necessary, but it's nice to allow it.

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
  • 7
    Also nice for autogenerated content (it's obviously trivial to add checks for the last element, but it needlessly complicates the code). – Matteo Italia Oct 18 '15 at 16:57
  • @MatteoItalia, Meet [`std::experimental::ostream_joiner`](http://en.cppreference.com/w/cpp/experimental/ostream_joiner) :) – chris Oct 18 '15 at 17:15
  • 2
    @MatteoItalia: _"it's obviously trivial to add checks for the last element"_ [That's not always true](https://stackoverflow.com/questions/20633403/is-there-a-trick-to-allow-mysql-to-ignore-a-trailing-comma-in-the-set-clause-o#comment30887606_20633403) – Lightness Races in Orbit Oct 18 '15 at 19:39
  • 1
    Well, its pretty trivial to generate each element as ` `, initialize `` to an empty string, and set it to `,` *after* you output each element. The overhead of resetting the separator after every element is unlikely to matter. – alephzero Oct 18 '15 at 21:38
  • 1
    This is also very useful if you want to sort your lines. – 5gon12eder Oct 31 '15 at 19:03
8

The trailing comma is a legacy from C, we can see this justified in the 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.

and this was also the reason cited in 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

We can find a more detailed background on the differing styles of initialization in the Annotated C++ Reference Manual(ARM), which explains the origins of some of the oddities in the grammar, it says the following about [dcl.init] with emphasis mine:

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.

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740