deducción de lista de inicialización y tipo de plantilla


Considere la función:

template<typename T>
void printme(T&& t) {
  for (auto i : t)
    std::cout << i;
}

O cualquier otra función que espere un parámetro con un tipo habilitado para begin()/end ().

¿Por qué es ilegal lo siguiente?

printme({'a', 'b', 'c'});

Cuando todos estos son legítimos:

printme(std::vector<char>({'a', 'b', 'c'}));
printme(std::string("abc"));
printme(std::array<char, 3> {'a', 'b', 'c'});

Podemos incluso escribir esto:

const auto il = {'a', 'b', 'c'};
printme(il);

O

printme<std::initializer_list<char>>({'a', 'b', 'c'});
Author: Praetorian, 2012-09-15

3 answers

Su primera línea printme({'a', 'b', 'c'}) es ilegal porque el argumento de la plantilla T no se pudo inferir. Si especifica explícitamente el argumento de la plantilla, funcionará, por ejemplo, printme<vector<char>>({'a', 'b', 'c'}) o printme<initializer_list<char>>({'a', 'b', 'c'}).

Los otros que enumeró son legales porque el argumento tiene un tipo bien definido, por lo que el argumento de plantilla T se puede deducir perfectamente.

Su fragmento con {[6] } también funciona porque il se considera que es de tipo std::initializer_list<char>, y por lo tanto el argumento de plantilla para printme() puede ser deducir.


La única parte "divertida" aquí es que auto elegirá el tipo std::initializer_list<char> pero el argumento de la plantilla no. Esto se debe a que § 14.8.2.5 / 5 del estándar C++11 establece explícitamente que este es un contexto no deducido para un argumento de plantilla:

Un parámetro de función para el cual el argumento asociado es una lista inicializadora (8.5.4) pero el parámetro no tiene std::initializer_list o referencia a un posible tipo std::initializer_list calificado para cv. [Ejemplo:

template<class T> void g(T);
g({1,2,3}); // error: no argument deduced for T

- ejemplo final]

Sin Embargo con auto, § 7.1.6.4/6 tiene soporte explícito para std::initializer_list<>

Si el inicializador es una lista de inicio entre corchetes (8.5.4), con std::initializer_list<U>.

 31
Author: Kevin Ballard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-14 20:59:36

También puede sobrecargar la función para tomar explícitamente un argumento de tipo initializer_list.

template<typename T>
void printme(std::initializer_list<T> t) {
  for (auto i : t)
    std::cout << i;
}
 7
Author: John Schug,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-14 23:11:49

Esto está cubierto específicamente en § 14.8.2.5 / 5

Un parámetro de función para el que el argumento asociado es un lista inicializador, pero el parámetro no tiene std::initializer_list o referencia a un cv posiblemente cualificado std::initializer_list tipo. [ Ejemplo:

template<class T> void g(T);
g({1,2,3}); // error: no argument deduced for T

- ejemplo final]

Para que funcione, puede especificar el tipo de argumento de la plantilla explícitamente.

printme<std::initializer_list<int>>( {1,2,3,4} );
 4
Author: Praetorian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-09-14 20:57:18