Pregunta

Desde C ++ 11, los contenedores de biblioteca estándar y std::string Haga que los constructores tomen una lista de inicializador. Este constructor tiene prioridad sobre otros constructores (incluso, como lo señaló @Johannesschaub-Litb en los comentarios, incluso ignorando otros criterios de "mejor partido"). Esto lleva a algunas trampas bien conocidas al convertir todos () formas de constructores a sus versiones arriesgadas {}

#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'
}

No pude encontrar el tercer ejemplo en este sitio, y la cosa surgió en el salónu003CC++> Chat (en discusión con @Rightfold, @abyx y @jerrycoffin), lo algo sorprendente es que convertir el std::string constructor toma un conteo y un personaje para usar {} en vez de (), cambia su significado de n copias del personaje al n-th carácter (típicamente de la tabla ASCII) seguido por el otro carácter.

Esto no se ve atrapado por la prohibición habitual de aparato ortopédico para reducir las conversiones, porque 65 es una expresión constante que puede representarse como un carbón y retendrá su valor original cuando se convierte en int (§8.5.4/7, bala 4) (gracias (gracias a @jerrycoffin).

Pregunta: ¿Hay más ejemplos al acecho en la biblioteca estándar donde la conversión de un () constructor de estilo para {} Estilo, ¿se combina con codicia por un constructor inicializador?

¿Fue útil?

Solución

Supongo que con sus ejemplos para std::vector<int> y std::string También quise cubrir los otros contenedores, por ejemplo, std::list<int>, std::deque<int>, etc. que tienen el mismo problema, obviamente, como std::vector<int>. Del mismo modo, el int no es el único tipo, ya que también se aplica a char, short, long y ellos unsigned Versión (posiblemente también algunos otros tipos integrales).

Creo que también hay std::valarray<T> Pero no estoy seguro si T se permite que sea de tipo integral. En realidad, creo que estos tienen una semántica diferente:

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

Hay algunas otras plantillas de clase C ++ estándar que toman una std::initializer_list<T> Como argumento, pero no creo que ninguno de estos tenga un constructor sobrecargado que se usara al usar paréntesis en lugar de aparatos ortopédicos.

Otros consejos

Solo buscando la ocurrencia de initializer_list.

  • Todas las secuencias, tienen los constructores como el de Vector:

    • deparar
    • dinarray
    • VENTA_LIST
    • lista
    • vector
  • valerray

  • Basic_string

  • Colecciones desordenadas, hay un constructor que toma un entero para determinar el recuento inicial de cubos.

    • desordenado_set
    • unordered_multiset

Creo que eso es todo.

#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 bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top