c++ - lists - ¿Por qué las llaves dobles{{}} vacías crean una std:: initializer_list<double> con un elemento, no cero?
constructor c++ 17 (2)
Tengo el siguiente constructor:
MyItem(std::initializer_list<double> l) {
std::cout << "l size " << l.size() << ")" << std::endl;
}
Lo que se llama más tarde con llaves dobles:
MyItem{{}}
El resultado que da l.size () es 1.
¿Cuál es la mecánica detrás de tal comportamiento?
Parece que el {} anidado juega como un constructor predeterminado para el único elemento, pero no entiendo muy bien por qué y cómo funciona la deducción de tipos aquí.
Cuando utiliza llaves ( MyItem
-lista) para inicializar el objeto MyItem
, el constructor de listas que ha mostrado es muy codicioso.
Estos pasarían una lista vacía:
MyItem foo({});
MyItem foo{std::initializer_list<double>{}};
Esto pasa una lista que contiene un solo elemento, un valor inicializado double
(0.0):
MyItem foo{{}};
Esto funciona porque hay ciertos contextos en los que simplemente puede usar llaves en lugar de un tipo conocido. Aquí, por la preferencia del constructor de listas, se sabe que la lista dada debe contener el double
.
Para completar, parece que pasa una lista vacía, pero en realidad el valor inicializa foo
si tiene un constructor predeterminado (o en casos especiales, hace algo casi equivalente). Si no hay un constructor predeterminado, elegiría el constructor de listas, como se muestra aquí .
MyItem foo{};
Esta expresión
MyItem{{}}
Denota la conversión explícita de tipos (la notación funcional).
Según el estándar de C ++ (5.2.3 conversión de tipo explícita (notación funcional))
- De manera similar, un especificador de tipo simple o un especificador de nombre de tipo seguido de una lista de iniciados de bracing crea un objeto temporal del tipo especificado direct-list-initialized (8.5.4) con la lista de init de braced y su valor Es ese objeto temporal como prvalue.
Class MyItem tiene el constructor de lista de inicializador de conversión
MyItem(std::initializer_list<double> l) {
std::cout << "l size " << l.size() << ")" << std::endl;
}
que se selecciona para la conversión explícita de tipos. De hecho es equivalente a la llamada.
MyItem( {{}} );
Entonces el constructor obtiene una lista de inicialización con un elemento
{ {} }
Un objeto escalar de tipo doble puede inicializarse con llaves vacías {}
.
Como resultado, la expresión crea un objeto temporal de tipo MyItem
que se inicializa mediante una lista de inicializadores que contiene un elemento de tipo double que se inicializa con valores mediante llaves vacías.