91

Code:

std::vector<int> x{1,2,3,4};
std::array<int, 4> y{{1,2,3,4}};

Why do I need double curly braces for std::array?

6
  • 1
    Do you actually need the second set of braces for std::array, or are you just getting a warning? std::array<int,4> y{1,2,3,4}; works for me. Commented Jul 9, 2012 at 17:36
  • 3
    @bames53: GCC is wrong in compiling that. Commented Jul 9, 2012 at 17:39
  • 14
    @Xeo: it's not "wrong" to compile an ill-formed program with a warning. Commented Jul 9, 2012 at 17:43
  • 3
    @Steve: True that. Let's say non-portable? Commented Jul 9, 2012 at 17:46
  • 2
    @Xeo: yeah, I use -Werror anyway for code I've written, so it doesn't harm my portability any. Others' mileage may vary, if they're lightweights or need to include header files written by lightweights :-) Commented Jul 9, 2012 at 17:47

2 Answers 2

77

std::array<T, N> is an aggregate: it doesn't have any user-declared constructors, not even one taking a std::initializer_list. Initialization using braces is performed using aggregate initialization, a feature of C++ that was inherited from C.

The "old style" of aggregate initialization uses the =:

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

With this old style of aggregate initialization, extra braces may be elided, so this is equivalent to:

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

However, these extra braces may only be elided "in a declaration of the form T x = { a };" (C++11 §8.5.1/11), that is, when the old style = is used . This rule allowing brace elision does not apply for direct list initialization. A footnote here reads: "Braces cannot be elided in other uses of list-initialization."

There is a defect report concerning this restriction: CWG defect #1270. If the proposed resolution is adopted, brace elision will be allowed for other forms of list initialization, and the following will be well-formed:

std::array<int, 4> y{ 1, 2, 3, 4 };

(Hat tip to Ville Voutilainen for finding the defect report.)

Sign up to request clarification or add additional context in comments.

7 Comments

So it's a failure of the abstraction model being presented for array?
@Mehrdad: It is uniform. What isn't uniform is the fact that you're initializing two completely different types.
@NicolBolas: I thought the whole point of uniformity was to use the same initialization syntax for different types? (Yes, I do understand what's happening... I'm just saying it's not "uniform" to the user, regardless of whether there's an explanation for it.)
@MarkRansom: Well, it's rather a quirk of the language, because std::array<int> y = {1,2,3,4}; works with a warning from Clang suggesting braces, instead of a hard error about not being allowed to "omit braces around initialization of subobject when using direct list-initialization".
@Xeo: Actually, brace elision is permitted in aggregate initialization, but (apparently) not when the direct list initialization syntax is used.
|
34

Because std::vector offers a constructor that takes in a std::initializer_list<T>, while std::array has no constructors and the {1, 2, 3, 4} braced init-list is in fact not interpreted as a std::initializer_list, but aggregate initialization for the inner C-style array of std::array (that's where the second set of braces comes from: One for std::array, one for the inner C-style member array).

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.