Why is the C++ initializer_list behavior for std::vector and std::array different?
Asked Answered
T

2

90

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?

Taillight answered 9/7, 2012 at 17:30 Comment(6)
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.Twelvetone
@bames53: GCC is wrong in compiling that.Finnell
@Xeo: it's not "wrong" to compile an ill-formed program with a warning.Gelatin
@Steve: True that. Let's say non-portable?Finnell
@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 :-)Gelatin
@bames53: yes it also works for me.Grigson
U
76

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.)

Undamped answered 9/7, 2012 at 17:32 Comment(7)
So it's a failure of the abstraction model being presented for array?Parkins
@Mehrdad: It is uniform. What isn't uniform is the fact that you're initializing two completely different types.Mcginnis
@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.)Monika
@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".Finnell
@Xeo: Actually, brace elision is permitted in aggregate initialization, but (apparently) not when the direct list initialization syntax is used.Undamped
However, the standard doesn't say anything about array having a single data member of type T[N]. In fact, to me it seems to imply that it should behave like an aggregate of N elements, not an aggregate containing a single element (see §23.3.2.1).Osculate
@juanchopanza: The specification says that it is an aggregate and that it "can be initialized with the syntax array<T, N> a = { initializer-list }; where initializer-list is a comma-separated list of up to N elements whose types are convertible to T." An implementation with a single data member of type T[N] (as demonstrated in the exposition in the specification), would meet this requirement, but would apparently not be initializable via the direct list initializer.Undamped
F
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).

Finnell answered 9/7, 2012 at 17:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.