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
}
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
iwans
  • 445
  • 3
  • 13
  • 2
    A [very similar question](https://stackoverflow.com/q/65193350/10871073) 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?) – Adrian Mole Dec 08 '20 at 11:28
  • 2
    @AdrianMole _but with a `struct` instead of a `std::pair`_ I would expect that the [std::pair](https://en.cppreference.com/w/cpp/utility/pair) is actually a (template) `struct`. ;-) – Scheff's Cat Dec 08 '20 at 11:31
  • 1
    @Scheff I can't disagree (even if I wanted to, which I don't). – Adrian Mole Dec 08 '20 at 11:32

2 Answers2

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.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • 2
    So why is `vector` different from `array`? – user253751 Dec 08 '20 at 23:10
  • 6
    `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. – Mooing Duck Dec 09 '20 at 00:23
  • 1
    @MooingDuck Ah, so it's actually two different mechanisms? An explicit constructor with vector, and a plain old aggregate initialization with array? – Peter - Reinstate Monica Dec 09 '20 at 11:08
  • @MooingDuck Also: Could I aggregate-initialize a std::vector (which surely also is an aggregate)? – Peter - Reinstate Monica Dec 09 '20 at 11:09
  • @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. – Mooing Duck Dec 09 '20 at 16:39
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 ) };
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335