with initialize argument c++ c++11 auto initializer-list type-deduction

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 un int var con el valor tomado de la lista de inicializadores", por lo tanto, su tipo es solo int y puede usarse en cualquier contexto más amplio ( int i = int{3} funcionará y auto i = int{3} puede deducir el tipo, porque el lado derecho es obviamente del tipo int )
  • {3} por sí mismo no tiene ningún tipo (no puede ser int , porque no es un valor sino una lista de inicializadores ), por lo que auto no funcionaría, pero, debido a que el comité consideró que auto 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 ++).