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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.