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'});
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>
.
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;
}
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 cualificadostd::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} );
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