Инициализация std::array круглыми скобками

struct A {
    int x, y, z;
} a = A(1, 2, 3);

#include <array>
auto b = std::array<int,3>(1, 2, 3);

error: array must be initialized with a brace-enclosed initializer

Почему можно инициализировать структуру с помощью такого синтаксиса, а std::array, который является структурной обёрткой над C-массивом, нельзя?


Ответы (1 шт):

Автор решения: HolyBlackCat

До С++20 оба варианта работали только с фигурными скобками: A{1, 2, 3} и std::array<int,3>{1, 2, 3} соответственно.

С первой записью все понятно, а вот вторая является сокращением от std::array<int,3>{{1, 2, 3}}. std::array - это структура с единственным полем-массивом (с неизвестным именем), поэтому одна пара скобок - для всей структуры, а вторая - для этого массива.

С++20 разрешил инициализацию агрегатов круглыми скобками. Агрегат (aggregate) - это структура без (самописных) конструкторов, либо массив.

Поэтому первая запись заработала с круглыми скобками. А про вторую читаем cppreference:

[круглые скобки ведут себя] as described in aggregate initialization except that ... there is no brace elision

Т.е. круглые скобки, в отличие от фигурных, не разрешают убирать лишние (фигурные) скобки.

И вроде бы это означает, что можно писать std::array<int,3>({1, 2, 3}). Но соль в том, что эта запись работала и в более ранних версиях, поскольку являлалсь сокращением от std::array<int,3>(std::array<int,3>{1, 2, 3}). По идее, сейчас она должна вместо этого разворачиваться в std::array<int,3>{{1, 2, 3}}, но как заметить разницу, и есть ли она вообще - непонятно.


В комментариях заметили, что в кланге и первая запись не компилируется. Они, редиски, до сих пор не поддержали инициализацию агрегатов круглыми скобками.

→ Ссылка