62 votes

Pourquoi l'initialisation d'un tableau de paires a-t-elle encore besoin d'accolades doubles en C ++ 14?

Avec le C++14 standard, l'initialisation d'un std::array pouvez aller avec un seul accolades (voir http://en.cppreference.com/w/cpp/container/array):

Ceci, cependant, ne fonctionne pas pour un std::array de std::pair.

Pourquoi ces travaux:

std::pair<int, int> p { 1, 2 };
std::array<int, 3> a {1, 2, 3};

mais n'est ce pas le travail:

std::array<std::pair<int, int>, 3> b {{1, 11}, {2, 22}, {3, 33}};

bien que cela ne fonctionne de nouveau?

std::array<std::pair<int, int>, 3> b {{{1, 11}, {2, 22}, {3, 33}}};

Aussi, pour l'exécution, l'initialisation d'un bon vieux tableau ne fonctionne pas avec le seul accolades

std::pair<int, int> c[3] {{1, 11}, {2, 22}, {3, 33}};

30voto

Jodocus Points 5413

Cela semble être une analyse ambuguity un peu similaire à la célèbre plus délicate à analyser. Je soupçonne ce qui se passe, c'est que:

Si vous écrivez

std::array<std::pair<int, int>, 3> b {{1, 11}, {2, 22}, {3, 33}};

le compilateur a deux manières d'interpréter la syntaxe:

  1. Vous effectuez un plein accolade de l'initialisation (sens ultrapériphériques corset se réfère à l'ensemble de l'initialisation de l' std::array, tandis que le premier a de plus intime on initialise le membre interne de la représentation de l' std::array ce qui est un réel C-Array). Cela ne parviennent pas à compiler, comme std::pair<int, int> par la suite ne peut pas être initialisé par 1 (tous les accolades sont utilisées). clang donnera une erreur de compilation, en indiquant exactement que:

    error: no viable conversion from 'int' to 'std::pair<int, int>'
     std::array<std::pair<int, int>, 3> a{{1, 11}, {2, 22}, {3, 33}};
                                              ^
    

    Notez également ce problème est résolu si il n'y a pas de membre interne d'agrégation être initialisé, c'est à dire

    std::pair<int, int> b[3] = {{1, 11}, {2, 22}, {3, 33}};
    

    va compiler amende globale de l'initialisation.

  2. (La façon dont il voulait dire.) Vous effectuez un corset-gommés de l'initialisation, le plus profond accolades sont donc pour l'ensemble de l'initialisation des paires individuelles, tandis que les accolades à l'intérieur de la matrice de représentations sont gommés. Notez que même si il n'y avait pas cette ambiguïté, comme souligné à juste titre dans rustyx de réponse, les règles de l'orthèse élision ne s'appliquent pas en tant que std::pair est pas de type d'agrégat de sorte que le programme serait encore mal formé.

Le compilateur va préférer l'option 1. En fournissant les extra accolades, vous effectuez le plein accolade de l'initialisation et de lever toute ambiguïté syntaxique.

14voto

rustyx Points 2722

Le C++14 corset élision de la règle s'applique uniquement aux subaggregate d'initialisation.

Ainsi, par exemple, quelque chose comme cela fonctionne:

std::array<std::array<int, 3>, 3> a{1, 11, 2, 22, 3, 33};

Ici, un agrégat d'agrégats peuvent être liste initialisée sans supplément de croisillons.

Mais std::pair n'est pas un agrégat (il a des constructeurs), de sorte que la règle ne s'applique pas.

Ce qui signifie que sans le corset élision de la règle, std::array, étant lui-même un agrégat avec un tableau à l'intérieur, a besoin d'un ensemble supplémentaire de croisillons afin d'être en liste-initialisé. Rappelez-vous que le modèle de classe array est mis en œuvre comme:

template<typename T, std::size_t N> 
struct array {
  T elems[N];
};

À la liste d'initialisation- il sans corset élision de la règle, vous avez besoin d'un jeu supplémentaire de croisillons pour se rendre à l' elems membre.

8voto

andreee Points 3115

Sans les doubles accolades, la déclaration est tout simplement ambigu. Considérons le code suivant:

    std::array<std::pair<int, int>, 1> a = {{ {1, 2} }};
    std::array<int, 2> b = { {1, 2} };

Sans doubles accolades dans la première définition, le compilateur va traiter { {1,2} } comme un scalaire liste d'initialisation pour array<int, 2>. Vous devez déclarer explicitement imbriquée moisa-init-liste pour que le compilateur de reconnaître que la liste interne est également globale initialisée (vs scalaire initialisé), tel qu'il peut construire un tableau de std::pair.

0voto

bartop Points 3747

En théorie, std::array doit être initialisé avec le regroupement d'initialisation. Donc en fait ceci:

std::array<int, 3> a {1, 2, 3};

est un sucre syntaxique pour cela:

std::array<int, 3> a {{1, 2, 3}};

Comme Vous le voyez, dans la première, il semble que je initialiser un tableau avec les valeurs, mais il est vraiment agrégation d'initialisation avec des entretoises d'initialisation de la liste. C'est clair comme le jour dans la seconde situation. Donc, c'est pour les débutants.

Ok, alors pourquoi ne pas ce travail?

std::array<std::pair<int, int>, 3> b {{1, 11}, {2, 22}, {3, 33}};

Eh bien, tout simplement, le compilateur ne peut pas distinguer ce type de syntaxe que Vous utilisez pour initialiser le tableau. {1, 11} peut être interprétée à la fois comme l'initialiseur de la liste et utilisez la première version ou il peut être interprété comme une paire pour aller avec la deuxième version.

Ce code:

std::array<std::pair<int, int>, 3> b {{{1, 11}, {2, 22}, {3, 33}}};.

supprime l'ambiguïté.

Source: http://en.cppreference.com/w/cpp/language/aggregate_initialization

-2voto

jwm Points 494

Je vais deviner ici.
La liste d'initialiseur pour std::array<T,n> doit être une liste d' T (ou trivialement constructable d' T). Alors que vous pourriez faire

std::array<std::pair<int,int>,3> b { std::pair{1,11}, std::pair{2,22}, std::pair{3,33} };

mais qu'est soigneusement détaillé. Afin d'obtenir la conversion en std::pair<int,int> vous voulez, vous devez fournir une liste d'initialiseur, de sorte

std::array<std::pair<int,int>,3> b {
    { // element 1
      { // initialize from:
        { 1,11 } // std::initializer_list
       }
     },
  ...
};

Je ne peux pas défendre cette autre, mais notez que l' std::vector<T, Allocator>::vector( std::initializer_list<T>, const Allocator& alloc=Allocator()) a été définie, mais std::array<T,n>::array( std::initializer_list<T> ) ne l'est pas. Ni est - std::pair<U,T>::pair( std::initializer_list<??> ) défini.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X