Why can't simple initialize (with braces) 2D std::array? [duplicate]
Asked Answered
M

1

63

Possible Duplicate:
c++ why initializer_list behavior for std::vector and std::array are different

I defined simple 2D array (3X2):

  std::array<std::array<int,3>,2> a {
    {1,2,3},
    {4,5,6}
  };

I was surprised this initialization does not work, with gcc4.5 error: too many initializers for 'std::array<std::array<int, 3u>, 2u>'

Why can't I use this syntax?

I found workarounds, one very funny with extra braces, but just wonder why the first, easiest approach is not valid?

Workarounds:

  // EXTRA BRACES
  std::array<std::array<int,3>,2> a {{
    {1,2,3},
    {4,5,6}
  }};

  // EXPLICIT CASTING
  std::array<std::array<int,3>,2> a {
    std::array<int,3>{1,2,3},
    std::array<int,3>{4,5,6}
  };

[UPDATE]

Ok, thanks to KerrekSB and comments I get the difference. So it seems that there is too little braces in my example, like in this C example:

struct B {
  int array[3];
};
struct A {
  B array[2];
};

B b = {{1,2,3}};
A a = {{
     {{1,2,3}},
     {{4,5,6}}
}};
Milling answered 11/10, 2012 at 16:42 Comment(3)
std::array is an aggregate.Steck
I would also expect this to work. BTW another workaround is to omit the inner braces, although it produces warnings on gcc 4.8.Delaminate
The multidimensional case isn't different from the single-dimensional case, though compiler support may vary. std::array<int, 2> a{1,2}; is ill-formed as well (gcc 4.7.2 will incorrectly accept such code; clang 3.1 will not). See the duplicate to which I linked above. The short answer is: this is a known defect in the C++11 language standard.Inhospitality
M
86

std::array<T, N> is an aggregate that contains a C array. To initialize it, you need outer braces for the class itself and inner braces for the C array:

std::array<int, 3> a1 = { { 1, 2, 3 } };

Applying this logic to a 2D array gives this:

std::array<std::array<int, 3>, 2> a2 { { { {1, 2, 3} }, { { 4, 5, 6} } } };
//                                   ^ ^ ^ ^            ^ ^
//                                   | | | |            | |
//                                   | +-|-+------------|-+
//                                   +-|-+-|------------+---- C++ class braces
//                                     |   |
//                                     +---+--- member C array braces
Maciemaciel answered 11/10, 2012 at 16:50 Comment(13)
But this works fine: std::array<int,3> a1 { 1, 2, 3 }; ?Milling
@PiotrNycz: Only if you're very sloppy and ignore all warnings. My compiler says, warning: missing braces around initialiser for ‘std::array<int, 3u>::value_type [3] {aka int [3]}’ [-Wmissing-braces].Maciemaciel
I get it now, thanks. I added to my question example with C.Milling
@Milling My reading of the standard is that std::array is not required to be implemented as a single element aggregate. I interpret §23.3.2.1 as stating that it can be initialized as per your first example. So I think the single brace syntax if fine.Delaminate
@Delaminate James McNellis wrote in comments this is known bug in C++11, maybe we can use single braces some day...Milling
@KerrekSB: Actually that is sanctioned by the standard as valid (it is called brace-elision), and there is even an example. I don't think that you should call sloppy someone that does exactly the same as the standard (8.5.1p12 is the particular example).Chloe
@DavidRodríguez-dribeas: Fair enough. Does the brace elision nest arbitrarily?Maciemaciel
@Milling as I said in another comment, you could completely eliminete the inner braces, and your example would probably compile (it does on my gcc 4.8 as well as on 4.6.3. In this case, brace elision kicks in.Delaminate
@Delaminate - yes it works - thanks. However still some different viewpoints in comments on this. I mean this works: a = {1,2,3,4,5,6}.Milling
@KerrekSB: Not really sure. My understanding is that it does, but I am not too familiar with the gory details of aggregate initialization (and to be honest I tend to write all braces myself, I have never encountered the nested std::array or any other case where so many unneded braces were needed)Chloe
@DavidRodríguez-dribeas: Well, I know that you can omit braces for multidimensional, naked C arrays, whose initializer you can write as a flat list. But I didn't know that this was generally also allowed for arbitrary aggregates... I'll check the standard again.Maciemaciel
@KerrekSB: I did check yesterday. It is allowed by the standard if the initialization is copy-initialization (T a = {}), and explicitly disallowed if it is direct-initialization (T a{}). There is a defect report filled to lift that restriction and allow brace-elision to occur with both syntaxes. I should have added this comment yesterday when I found out.Chloe
This is a great comment. I had always wondered why we needed the double braces but hadn't put that much thought into it. It makes much more sense now.Xylon

© 2022 - 2024 — McMap. All rights reserved.