with - named initializer list c++




Por que a inicialização da matriz de pares ainda precisa de chaves duplas em C++ 14? (4)

Com o padrão C ++ 14, a inicialização de um std::array pode ser feita com chaves individuais (consulte http://en.cppreference.com/w/cpp/container/array ):

Isso, no entanto, não funciona para um std::array de std::pair .

Por que estes funcionam:

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

mas isso não funciona:

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

enquanto isso funciona de novo?

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

Além disso, para conclusão, a inicialização de uma boa matriz antiga funciona com chaves individuais

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

A regra de elisão da chave C ++ 14 aplica-se apenas à inicialização subaggregada.

Então, por exemplo, algo assim funciona:

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

Aqui, um agregado de agregados pode ser inicializado por lista sem chaves extras.

Mas std::pair não é um aggregate (tem construtores), então a regra não se aplica.

O que significa que, sem a regra de elisão da chave, std::array , sendo ele próprio um agregado com uma matriz dentro, precisa de um conjunto extra de chaves para ser inicializado por lista . Lembre-se de que a array modelos de classes é implementada como:

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

Para listar-inicializá- lo sem a regra de elisão de chave, você precisa de um conjunto extra de chaves para chegar ao membro de elems .


Em teoria, std::array deve ser inicializado com inicialização agregada. Então, na verdade isso:

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

é um açúcar sintático para isso:

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

Como você vê, no primeiro parece que eu inicializo array com valores, mas é realmente uma inicialização agregada com uma lista de inicialização suportada. Isto é claro como um dia na segunda situação. Então, isso é para começar.

Ok então por que isso não funciona?

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

Bem, simplesmente coloque - o compilador não consegue distinguir que tipo de sintaxe você está usando para inicializar o array. {1, 11} pode ser interpretado como lista inicializadora e usar a primeira versão ou pode ser interpretado como um par e ir com a segunda versão.

Este código:

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

elimina a ambigüidade.

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


Eu vou adivinhar aqui.
A lista de inicializadores para std::array<T,n> deve ser uma lista de T (ou trivialmente construtível para T ). Então você poderia fazer

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

mas isso é tediosamente detalhado. Para obter a conversão para std::pair<int,int> você quer, você precisa fornecer uma lista inicializadora, então

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

Eu não posso defender isso ainda mais, mas observe que std::vector<T, Allocator>::vector( std::initializer_list<T>, const Allocator& alloc=Allocator()) é definido, mas std::array<T,n>::array( std::initializer_list<T> ) não é. Nem é std::pair<U,T>::pair( std::initializer_list<??> ) definido.


Sem as chaves duplas, a declaração é simplesmente ambígua. Considere o seguinte código:

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

Sem chaves duplas na primeira definição, o compilador tratará { {1,2} } como uma lista de inicialização escalar para array<int, 2> . Você precisa declarar uma lista-init braced aninhada explícita para que o compilador reconheça que a lista interna também é inicializada por agregado (vs. escalar inicializada), de modo que possa construir uma matriz de std::pair .





initializer-list