argument - c++ initialize class with parameters
¿Por qué auto x{3} deduce una initializer_list? (1)
Me encanta el
auto
en C ++ 11.
Es maravilloso.
Pero tiene una inconsistencia que realmente me pone de los nervios, porque me tropiezo todo el tiempo:
int i = 3; // i is an int with value 3
int i = int{3}; // i is an int with value 3
int i(3); // i is an int with value 3 (possibly narrowing, not in this case)
int i{3}; // i is an int with value 3
auto i = 3; // i is an int with value 3
auto i = int{3}; // i is an int with value 3
auto i(3); // i is an int with value 3
auto i{3}; // wtf, i is a std::initializer_list<int>?!
Este comportamiento extraño es confuso para los recién llegados y molesto para los usuarios experimentados: C ++ tiene suficientes pequeñas inconsistencias y casos esquimales que uno debe tener en cuenta tal como están. ¿Alguien puede explicar por qué el comité de normas decidió introducir uno nuevo en este caso?
Podría entenderlo si declarar una variable de tipo
std::initializer_list
era algo útil o que se hacía con frecuencia, pero en mi experiencia casi nunca es deliberado, y en los raros casos en los que quisiste hacerlo, cualquiera de
std::initializer_list<int> l{3};
auto l = std::initializer_list<int>{3};
auto l = {3}; // No need to specify the type
funcionaría bien.
Entonces, ¿cuál es la razón detrás del caso especial para
auto x{i}
?
Para resumir la historia larga:
-
una expresión de inicializador entre paréntesis
{}
no tiene ningún tipo en sí misma -
auto
tiene que inferir información de tipo -
int{3}
obviamente significa "crear unint
var con el valor tomado de la lista de inicializadores", por lo tanto, su tipo es soloint
y puede usarse en cualquier contexto más amplio (int i = int{3}
funcionará yauto i = int{3}
puede deducir el tipo, porque el lado derecho es obviamente del tipoint
) -
{3}
por sí mismo no tiene ningún tipo (no puede serint
, porque no es un valor sino una lista de inicializadores ), por lo queauto
no funcionaría, pero, debido a que el comité consideró queauto
debería funcionar en este caso, decidieron que el tipo "mejor" para la lista de inicializadores (sí, sin tipo por definición) sería ...std::initializer_list
, como ya habrás adivinado.
Pero, como usted señaló, esto hizo que todo el comportamiento del
auto
semánticamente inconsistente.
Es por eso que hubo propuestas para cambiarlo, es decir,
N3681
,
N3912
y
N3922
, presentadas al comité.
La propuesta anterior fue RECHAZADA como FI3 debido a que no hubo consenso del comité sobre este asunto,
http://isocpp.org/files/papers/n3852.html#FI3
, actual (
N3922
) fue
adoptada
ca.
Q1 de 2015
;
tl; dr puede suponer que los compiladores que cumplen con los estándares 1 con soporte C ++ de vanguardia 2 tienen la nueva semántica más sensata que ya está en su lugar o la tendrán en breve.
El Comité de Normalización reconoció el problema al adoptar N3922 en el borrador de C ++ 17.
- entonces es
auto x1 = { 1, 2 }; // decltype(x1) is std::initializer_list<int>
auto x2 = { 1, 2.0 }; // error: cannot deduce element type
auto x3{ 1, 2 }; // error: not a single element
auto x4 = { 3 }; // decltype(x4) is std::initializer_list<int>
auto x5{ 3 }; // decltype(x5) is int
ahora, para bien o para mal.
Otras lecturas:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3681.html
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3912.html
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3922.html
scottmeyers.blogspot.com/2014/03/…
http://herbsutter.com/2014/11/24/updates-to-my-trip-report/
1 GCC 5.1 (y superior) aparentemente usa N3922 incluso en modo C ++ 11 / C ++ 14
2 Clang 3.8, con la advertencia
Este es un cambio incompatible con versiones anteriores que se aplica a todas las versiones de idioma que permiten la deducción de tipo de auto (por solicitud del comité de C ++).