This C++11 code works fine for me:
#include <iostream>
#include <vector>
#include <array>
using namespace std;
struct str {
int first, last;
};
vector<str> fields {
{1,2}, {3,4}, {5,6}
};
int main()
{
for (str s : fields)
cout << s.first << " " << s.last << endl;
}
It prints the six expected values.
But if I change vector<str>
to array<str,3>
, gcc gives me this error: "too many initializers for ‘std::array’".
If I change the initialization of fields
thus:
array<str,3> fields {
str{1,2}, str{3,4}, str{5,6}
};
Things work nicely.
So why do I need str{1,2}
when using std::array
, but only {1,2}
when using std::vector
?
See cppreference's section on aggregate initialization.
The effects of aggregate initialization are:
Each array element or non-static class member, in order of array subscript/appearance in the class definition, is copy-initialized from
the corresponding clause of the initializer list.
If the initializer clause is a nested braced-init-list, the corresponding class member is itself an aggregate: aggregate
initialization is recursive.
This means that if you had an aggregate inside your struct, such as:
struct str {
struct asdf
{
int first, last;
} asdf;
};
asdf
would be initialized by the first nested brace-init-list, i.e. { { 1, 2 } }
. The reason why you generally need two pairs of braces is because the nested brace-init-list initializes the underlying aggregate in std::array
(for example, T a[N]
).
However, you can still initialize your array like this:
array<str,3> fields {
1, 2, 3, 4, 5, 6
};
or:
array<str,3> fields { {
1, 2, 3, 4, 5, 6
} };
instead.
On the other hand, how you initialize your vector is covered by list initialization. std::vector
has a constructor that accepts an std::initializer_list
.
The effects of list initialization of an object of type T are:
Note that you wouldn't be able to initialize your vector ( like this:
vector<str> fields {
1,2, 3,4, 5,6
};
but:
vector<int> fields {
1,2, 3,4, 5,6
};
is perfectly fine.
It's because array initialization is built a bit different from vector.
To initialize an array you need to use two braces.
Because of a syntax feature you can skip it if you initialize just one object.
So the following is ok:
array{1,2,3} -> array{{1,2,3}}
But in your example you initialize multiple objects so the compiler doesn't add additional braces. Using two braces fixes that.
array<str,3> fields {{
{1,2}, {3,4}, {5,6}
}};