Why can't std::array<std::pair<int,int>, 3> be initialized using nested initializer lists, but std::vector<std::pair<int,int>> can?
Asked Answered
S

2

21

See this example: https://godbolt.org/z/5PqYWP

How come this array of pairs can't be initialized in the same way as a vector of pairs?

#include <vector>
#include <array>

int main()
{
    std::vector<std::pair<int,int>>    v{{1,2},{3,4},{5,6}}; // succeeds 
    std::array <std::pair<int,int>, 3> a{{1,2},{3,4},{5,6}}; // fails to compile
}
Socrates answered 8/12, 2020 at 11:25 Comment(3)
A very similar question was asked today, but with a struct instead of a std::pair. But the answer there is much the same as any here would be, IMHO. (Or maybe not - that one is about an assignment rather than a constructor?)Nonaggression
@AdrianMole but with a struct instead of a std::pair I would expect that the std::pair is actually a (template) struct. ;-)Lewes
@Scheff I can't disagree (even if I wanted to, which I don't).Nonaggression
S
24

You need to add an outer pair of braces to initialize the std::array<...> object itself:

std::array <std::pair<int,int>, 3> a{{{1,2},{3,4},{5,6}}};

The outermost pair is for the array object, the second pair is for the aggregate array inside the object. Then the list of elements in the array.

Sperry answered 8/12, 2020 at 11:28 Comment(5)
So why is vector different from array?Hostility
std::array is an aggregate, so you need {} to construct the std::array class, and a {} to construct it's member array. std::vector has a constructor that takes a std::initializer_list, so the {} to construct the vector automatically calls that.Triiodomethane
@MooingDuck Ah, so it's actually two different mechanisms? An explicit constructor with vector, and a plain old aggregate initialization with array?Incumbency
@MooingDuck Also: Could I aggregate-initialize a std::vector (which surely also is an aggregate)?Incumbency
@Peter-ReinstateMonica: No. an "Aggregate" is basically "a class whose members are all public and has no explicit constructors", which lets you directly construct the array member of the std::array. Instead, std::vector has private members that you can't access yourself, and custom constructors, so it's not an aggregate.Triiodomethane
P
14

Specializations of the class template std::array represent aggregates that enclose another aggregate.

The reason of the error is that the first braced initializer in this declaration

std::array <std::pair<int,int>, 3> a{{1,2},{3,4},{5,6}};
                                     ^^^^^

is considered as an initializer of the inner aggregate. In this case the following braced initializers are considered as redundant initializers.

So you can write either

std::array <std::pair<int, int>, 3> a{ { {1,2},{3,4},{5,6} } };
                                       ^                   ^
                                       |the inner aggregate|

or like

std::array <std::pair<int, int>, 3> a{ std::make_pair( 1, 2 ), std::make_pair( 3, 4 ), std::make_pair( 5, 6 ) };
Paxton answered 8/12, 2020 at 11:41 Comment(4)
It's worth mentioning that std::array doesn't have a initializer_list constructor, which vector does.Socrates
@Socrates std::array is an aggregate. It does not have user declared constructors.:)Paxton
@VladfromMoscow That's too bad, isn't it?Incumbency
@Peter-ReinstateMonica I do not think so. This class (aggregate) simulates an array that in turn is an aggregate.Paxton

© 2022 - 2024 — McMap. All rights reserved.