Liste d'initialisation pour un array et un vecteur

L’auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

Bonjour,

En utilisant un std::array de structure, j’ai remarqué que l’initialisation ne se faisait pas comme pour un std::vector :

#include <array>
#include <vector>

struct A { std::string name; };

int main() {
    std::array<A, 5> my_array {{
        {"Name 1"}, {"Name 2"}, {"Name 3"}, {"Name 4"}, {"Name 5"}
    }};
    
    std::vector<A> my_vector{
        {"Name 1"}, {"Name 2"}, {"Name 3"}, {"Name 4"}, {"Name 5"}
    };
}

Ma question est d’où vient cette paire d’accolades supplémentaire (j’ai cru comprendre que ça avait à voir avec une histoire d’agrégat..) ? Et pourquoi cette différence avec l’initialisation d’un vecteur ?

Merci pour vos réponses!

+1 -0

Cette réponse a aidé l’auteur du sujet

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. :)

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte