Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does initialization of array of pairs still need double braces in C++14?

With the C++14 standard, the initialization of an std::array can go with single braces (see http://en.cppreference.com/w/cpp/container/array):

This, however, does not work for an std::array of std::pair.

Why do these work:

std::pair<int, int> p { 1, 2 }; std::array<int, 3> a {1, 2, 3}; 

but does this not work:

std::array<std::pair<int, int>, 3> b {{1, 11}, {2, 22}, {3, 33}}; 

while this does work again?

std::array<std::pair<int, int>, 3> b {{{1, 11}, {2, 22}, {3, 33}}}; 

Also, for completion, the initialization of a good old array does work with single braces

std::pair<int, int> c[3] {{1, 11}, {2, 22}, {3, 33}}; 
like image 625
Chiel Avatar asked May 30 '18 07:05

Chiel


People also ask

What is double brace initialization?

Double brace initialisation creates an anonymous class derived from the specified class (the outer braces), and provides an initialiser block within that class (the inner braces). e.g. new ArrayList<Integer>() {{ add(1); add(2); }};

What is brace initialization?

If a class has non-default constructors, the order in which class members appear in the brace initializer is the order in which the corresponding parameters appear in the constructor, not the order in which the members are declared (as with class_a in the previous example).


1 Answers

This appears to be a parsing ambuguity somewhat similar to the famous most vexing parse. I suspect what's going on is that:

If you write

std::array<std::pair<int, int>, 3> b {{1, 11}, {2, 22}, {3, 33}}; 

the compiler has two ways to interpret the syntax:

  1. You perform a full-brace initialization (meaning the outermost brace refers to the aggregate initialization of the std::array, while the first innermost one initializes the internal member representation of std::array which is a real C-Array). This will fail to compile, as std::pair<int, int> subsequently cannot be initialized by 1 (all braces are used up). clang will give a compiler error indicating exactly that:

    error: no viable conversion from 'int' to 'std::pair<int, int>'  std::array<std::pair<int, int>, 3> a{{1, 11}, {2, 22}, {3, 33}};                                           ^ 

    Note also this problem is resolved if there is no internal member aggregate to be initialized, i.e.

    std::pair<int, int> b[3] = {{1, 11}, {2, 22}, {3, 33}}; 

    will compile just fine as aggregate initialization.

  2. (The way you meant it.) You perform a brace-elided initialization, the innermost braces therefore are for aggregate-initialization of the individual pairs, while the braces for the internal array representations are elided. Note that even if there wasn't this ambiguity, as correctly pointed out in rustyx's answer, the rules of brace elision do not apply as std::pair is no aggregate type so the program would still be ill-formed.

The compiler will prefer option 1. By providing the extra braces, you perform the full-brace initialization and lift any syntactical ambiguity.

like image 133
Jodocus Avatar answered Oct 05 '22 04:10

Jodocus