tipos tipo que parametros lenguaje hacer funciones funcion existen con como c++ c++11 variadic-templates

c++ - parametros - ¿Por qué el paquete de parámetros de la plantilla no se deduce a varios argumentos de tipo en la llamada de función?



tipo funcion c++ (2)

Lo que está sucediendo es que una función de plantilla con una class... Ts paquete de parámetros de plantilla class... Ts , y un tipo de parámetro (P) de foo<Ts...> se está deduciendo de un tipo de argumento (A) de foo<int> .

14.8.2.5/9 dice de esto:

Si P tiene un formulario que contiene <T> o <i> [lo hace], entonces cada argumento Pi [ Ts... ] de la lista de argumentos de plantilla respectiva P se compara con el argumento correspondiente Ai [ int ] de la plantilla correspondiente lista de argumentos de A. Si la lista de argumentos de plantilla de P contiene una expansión de paquete que no es el último argumento de plantilla, toda la lista de argumentos de plantilla es un contexto no deducido. [la expansión del paquete es la última, por lo que el anterior no se aplica] Si Pi es una expansión del paquete [ Ts... , lo es], entonces el patrón de Pi se compara con cada argumento restante en la lista de argumentos de la plantilla de A ( int ) . Cada comparación deduce argumentos de plantilla para las posiciones posteriores en los paquetes de parámetros de plantilla expandidos por Pi.

Por lo tanto, la class... Ts debe deducirse como la lista de un elemento int , y, por consiguiente, la plantilla de función debe instanciarse con el tipo de parámetro const foo<int>& , y ser viable.

Es un error de compilación. Su código está bien formado.

Más sucintamente esto está bien formado:

template<class A, class... B> struct S { }; template<class... C> void f(S<C...>) { } int main() { f(S<int>()); }

pero falla de manera similar en al menos gcc 4.7.2 con:

error: parameter 1 of ‘void f(S<C ...>) [with C = {int, C}]’ has incomplete type ‘S<int, C>’

C se deduce incorrectamente como C = {int, C} (una recursión sin sentido) en lugar de C = {int} . La deducción rota de C lleva a una mayor basura que S<int, C> tiene un tipo incompleto.

Tengo una clase con plantilla en un paquete de parámetros y parámetros de tipo, y estoy confundido acerca de la deducción de tipo de este tipo; al escribir un operador de transmisión de salida, descubrí un paquete de parámetros en el operator<< no coincidirá con los parámetros de tipo y paquete para la clase de plantilla:

#include <iostream> template<class T, class... Ts> struct foo { /* ... */ }; template< class... Ts > std::ostream& operator<<( std::ostream& os, const foo<Ts...>& ) { return os << 42; } int main() { std::cout << foo<int>(); }

Esto no se compila tanto en gcc-4.7.2 como en clang-3.0, así que supongo que no entiendo las reglas aquí.

gcc dice (donde la línea 16 es la llamada del flujo de salida):

t.cpp:16:28: error: cannot bind ‘std::ostream {aka std::basic_ostream<char>}’ lvalue to ‘std::basic_ostream<char>&&’ In file included from /usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/iostream:40:0, from t.cpp:1: /usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../include/c++/4.7.2/ostream:600:5: error: initializing argument 1 of ‘std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = foo<int>]’

y clang dice:

t.cpp:16:16: error: invalid operands to binary expression (''ostream'' (aka ''basic_ostream<char>'') and ''foo<int>'') std::cout << foo<int>(); ~~~~~~~~~ ^ ~~~~~~~~~~ [--- snip: lots of non-viable candidates from standard library ---] t.cpp:8:19: note: candidate template ignored: substitution failure [with Ts = <>] std::ostream& operator<<( std::ostream& os, const foo<Ts...>& ) ^

¿Podría alguien explicarme por qué el paquete de parámetros para el operator<< no se puede deducir como el tipo de parámetro y el paquete de parámetros para foo ?


Wow, hubiera pensado que esto ya estaba arreglado, pero aún no funciona en las versiones preliminares de GCC 4.9 y Clang 3.4 (cortesía de Coliru ).

La solución es simple: use la especialización parcial para deducir los argumentos de la plantilla en otro lugar.

template<class... Ts> struct foo; // unimplemented template<class T, class... Ts> struct foo< T, Ts ... > // specialization for at least one argument { /* ... */ }; template< class... Ts > std::ostream& operator<<( std::ostream& os, const foo<Ts...>& ) { return os << 42; }

No sé por qué GCC y Clang no pueden resolver este error de años imitando la solución en el caso general. Los proveedores de compiladores tal vez enfrentan una desafortunada elección entre rendimiento y corrección.