Инициализация 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 шт):
До С++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}}, но как заметить разницу, и есть ли она вообще - непонятно.
В комментариях заметили, что в кланге и первая запись не компилируется. Они, редиски, до сих пор не поддержали инициализацию агрегатов круглыми скобками.