Why does this work:
std::pair<int, int> p = {1,2}; std::vector<std::pair<int, int>> vp = { {1,2}, {3,4} };
But this doesn't?
std::array<int, 2> a = {1,2}; // still ok std::vector<std::array<int, 2>> va = { {1,2}, {3,4} };
Using g++ 4.5.1 with -std=c++0x
, the second line fails with:
error: could not convert
‘{{1, 2}, {3, 4}}’
to‘std::vector<std::array<int, 2u> >’
Thanks
You cannot store arrays in a vector or any other container. The type of the elements to be stored in a container (called the container's value type) must be both copy constructible and assignable.
Vectors in C++ are sequence containers representing arrays that can change in size. They use contiguous storage locations for their elements, which means that their elements can also be accessed using offsets on regular pointers to its elements, and just as efficiently as in arrays.
We can think of a vector as a list that has one dimension. It is a row of data. An array is a list that is arranged in multiple dimensions. A two-dimensional array is a vector of vectors that are all of the same length.
Vector is template class and is C++ only construct whereas arrays are built-in language construct and present in both C and C++. Vector are implemented as dynamic arrays with list interface whereas arrays can be implemented as statically or dynamically with primitive data type interface.
Unfortunately, std::array
does not have an initializer list constructor. Indeed, it has no user-defined constructor whatsoever -- this "feature" is a leftover from C++03 where omitting all user-defined constructors was the only way to enable the C-style brace initialization. It is IMHO a defect in the current standard.
So why doesn't built-in brace initialization work in this case? Let's see what std::array
looks like under the hood:
template <typename T, int i> struct array { T data[i]; // ... }
Ok, so doesn't that mean we'd have to use double braces in the initializer (one pair for array
, another pair for the data
member?
std::array<int, 2> a = { {1, 2} };
C (and consequently C++) has a special rule about brace elision, permitting the omission of the inner braces unless there is an ambiguity. array
exploits this feature, allowing us to write
std::array<int, 2> a = { 1, 2 };
So why doesn't the example in the original post work? Because brace elision is only permitted in the context of a C-style aggregate initialization, not if there's anything more complicated involved, such as an user-defined initializer list constructor.
The following should work, though, as ugly as it is:
std::vector<std::array<int, 2>> vp = { {{1,2}}, {{3,4}} };
The fact that it does not, at least on gcc 4.5 and gcc 4.6, seems to me to indicate a compiler bug. I'm not completely sure about it, though.
This question is somewhat relevant: How do I initialize a member array with an initializer_list?
This works:
std::vector<std::array<int, 2>> va = { std::array<int, 2>{1,2}, std::array<int, 2>{3,4} };
Digging deeper, it seems that std::pair has a constructor that takes an initialiser list, but std::array doesn't:
std::pair<int, int> p ({1,2}) ; // OK std::array<int, 2> a ({1,2}) ; // Invalid
But now I'm out of my depth.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With