Cette réponse sur StackOverflow devrait t’éclairer un peu. Je la remets ci-dessous.
std::array
is defined as a structure that contains an array.
Thus the first pair of braces are used to initialize data members of the structure that is the > array.
The second pair of braces is used to initialize the array within the structure.
And the third pairs of braces are used to initialize each object of type std::pair.
To be more precise then according to the C++ Standard (23.3.2.1 Class template array overview)
2 An array is an aggregate (8.5.1) that can be initialized with the
syntax
array<T, N> a = { initializer-list };
where initializer-list is a comma-separated list of up to N elements
whose types are convertible to T.
Depuis C++14, il est possible de ne plus utiliser qu’une paire d’accolades {}
. Le code suivant est valide.
std::array<int, 5> entiers { 1, 2, 3, 4, 5 };
Maintenant, pourquoi dans ton cas tu as toujours besoins de deux paires, même en C++14 et supérieur, alors que pour std::vector
ce n’est pas le cas ? Explorons tout ça.
D’abord, il faut savoir que, selon la documentation, on a affaire à un agrégat car std::array
est en interne un tableau C.
If the initializer clause is an expression, implicit conversions are allowed as per copy-initialization, except, for list-initialization form, narrowing conversions are prohibited (since C++11).
Déjà, ça veut dire que le code suivant compile sans problème car conversion implicite d’une std::string
vers un A
.
std::array<A, 5> conversion { "Name 1"s, "Name 2"s, "Name 3"s, "Name 4"s, "Name 5"s };
Le code est aussi fonctionnel quand on donne explicitement des objets de type A
.
std::array<A, 5> objets_a
{
A{"Name 1"s}, A{"Name 2"s}, A{"Name 3"s}, A{"Name 4"s}, A{"Name 5"s}
};
Par contre, juste donner { "Texte" }
ne marche pas, car on n’a pas affaire à une expression. La preuve, si tu essayes de l’utiliser avec decltype
, tu vas avoir des erreurs.
prog.cc:8:14: error: expected expression
decltype({ "Name"s }) X{};
^
1 error generated.
Et dans le cas où on ne passe pas une expression, alors on tombe dans le cas suivant.
If the initializer clause is a nested braced-init-list (which is not an expression), the corresponding array element/class member/public base (since C++17) is list-initialized from that clause: aggregate initialization is recursive.
Si tu ne mets qu’un élément, alors le compilateur voit une nested braced-init-list et il la parcoure pour ajouter chaque élément. Le code suivant compile donc.
std::array<A, 5> unique {{"Name 1"s}};
Mais quand tu lui en donne plusieurs, le compilateur est tout perdu et il se plaint qu’il a trop d’éléments. Par contre, si tu rajoute une paire d’accolades, là il retrouve ces petits car il se met à parcourir une nested braced-init-list. La document dit list-initialized. Chaque objet de cette sous-liste ({ "NameX" }
) est converti implicitement en A
.
std::array<A, 5> my_array {{
{"Name 1"s}, {"Name 2"s}, {"Name 3"s}, {"Name 4"s}, {"Name 5"s}
}};
Les règles sont assez compliquées et il se peut que je dise des bêtises. Les pros du C++ pourront confirmer / infirmer / compléter mes explications.