Pergunta

Desde C ++ 11, os contêineres da biblioteca padrão e std::string ter construtores que tomam uma lista de inicializador. Esse construtor tem precedência sobre outros construtores (mesmo, como apontado por @Johannesschaub-Litb nos comentários, até ignorando outros critérios de "melhor correspondência"). Isso leva a algumas armadilhas bem conhecidas ao converter todos os parênteses () formas de construtores para suas versões apoiadas {}

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
#include <string>

void print(std::vector<int> const& v)
{
    std::copy(begin(v), end(v), std::ostream_iterator<int>(std::cout, ","));
    std::cout << "\n";
}

void print(std::string const& s)
{
    std::cout << s << "\n";
}

int main()
{
    // well-known 
    print(std::vector<int>{ 11, 22 });  // 11, 22, not 11 copies of 22
    print(std::vector<int>{ 11 });      // 11,     not 11 copies of 0

    // more surprising
    print(std::string{ 65, 'C' });      // AC,     not 65 copies of 'C'
}

Não consegui encontrar o terceiro exemplo neste site, e a coisa surgiu no loungeu003CC++> bate -papo (em discussão com @rightfold, @abyx e @jerrycoffin), o que é surpreendente é que a conversão do std::string construtor fazendo uma contagem e um personagem para usar {} ao invés de (), muda seu significado de n cópias do personagem para o n-th caractere (normalmente da tabela ASCII) seguido pelo outro caractere.

Isso não é capturado pela proibição usual de nascentes de estreitar conversões, porque 65 é uma expressão constante que pode ser representada como um carvão e manterá seu valor original quando convertido de volta em int (§8.5.4/7, bala 4) (obrigado para @jerrycoffin).

Pergunta: Existem mais exemplos à espreita na biblioteca padrão onde a conversão de um () construtor de estilo para {} Estilo, é avidamente combinado por um construtor da lista inicial?

Foi útil?

Solução

Suponho, com seus exemplos para std::vector<int> e std::string você pretendia também cobrir os outros recipientes, por exemplo, std::list<int>, std::deque<int>, etc. que têm o mesmo problema, obviamente, como std::vector<int>. Da mesma forma, o int não é o único tipo que também se aplica a char, short, long e deles unsigned Versão (possivelmente alguns outros tipos integrais também).

Eu acho que há também std::valarray<T> Mas não tenho certeza se T é permitido ser o tipo integral. Na verdade, acho que eles têm semântica diferente:

std::valarray<double>(0.0, 3);
std::valarray<double>{0.0, 3};

Existem alguns outros modelos de classe C ++ padrão que tomam um std::initializer_list<T> Como argumento, mas não acho que nenhum deles tenha um construtor sobrecarregado que seria usado ao usar parênteses em vez de aparelho.

Outras dicas

Apenas procurando a ocorrência de initializer_list.

  • Todas as seqüências, elas têm os construtores como o do vetor:

    • deque
    • Dynarray
    • Forward_list
    • Lista
    • vetor
  • Valarray

  • Basic_String

  • Coleções não ordenadas, existe um construtor que leva um número inteiro para determinar a contagem inicial de caçambas.

    • UNODERED_SET
    • UNODERED_MULTISET

Eu acho que é tudo isso.

#include <unordered_set>
#include <iostream>

int main() {
    std::unordered_set<int> f (3);
    std::unordered_set<int> g {3};
    std::cout << f.size() << "/" << g.size() << std::endl; // prints 0/1.
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top