¿Por qué la deducción del argumento de la plantilla no funciona aquí?

Creé dos funciones simples que obtienen los parámetros de la plantilla y una estructura vacía que define un tipo:

//S::type results in T& template  struct S { typedef typename T& type; }; //Example 1: get one parameter by reference and return it by value template  A temp(typename S::type a1) { return a1; } //Example 2: get two parameters by reference, perform the sum and return it template  B temp2(typename S::type a1, B a2)//typename struct S::type a2) { return a1 + a2; } 

El tipo de argumento se aplica a la estructura S para obtener la referencia. Los llamo con algunos valores enteros pero el comstackdor no puede deducir los argumentos:

 int main() { char c=6; int d=7; int res = temp(c); int res2 = temp2(d,7); } 

Error 1 error C2783: ‘A temp (S :: type)’: no ​​se pudo deducir argumento de plantilla para ‘A’

Error 2 error C2783: ‘B temp2 (S :: tipo, B)’: no ​​se pudo deducir el argumento de la plantilla para ‘A’


¿Por qué está pasando esto? ¿Es tan difícil de ver que los argumentos de la plantilla sean valores char e int ?

Al igual que la primera nota, el nombre del tipo de letra se usa cuando mencionas un nombre dependiente . Entonces no lo necesitas aquí.

 template  struct S { typedef T& type; }; 

Con respecto a la typename S::type instancias de plantilla, el problema es que typename S::type caracteriza un contexto no deducido para A. Cuando un parámetro de plantilla se usa solo en un contexto no deducido (el caso de A en sus funciones) no se toma en consideración para deducción del argumento de la plantilla. Los detalles se encuentran en la sección 14.8.2.4 del Estándar C ++ (2003).

Para hacer que su llamada funcione, debe especificar explícitamente el tipo:

 temp(c); 

Se ve como un contexto no deducido. De acuerdo con el estándar C ++ 14.8.2.4/4:

Los contextos no dictados son:

  • El especificador de nombre nested de un tipo que se especificó utilizando un id calificado .
  • Un tipo que es un id de plantilla en el que uno o más de los argumentos de plantilla es una expresión que hace referencia a un parámetro de plantilla .

Cuando se especifica un nombre de tipo de una manera que incluye un contexto no deducido, todos los tipos que comprenden ese nombre de tipo tampoco se escriben. Sin embargo, un tipo compuesto puede incluir tanto los tipos deducidos como los no deducidos. [ Ejemplo : si un tipo se especifica como A::B , tanto T como T2 no se escriben. Del mismo modo, si un tipo se especifica como A::X , I , J y T no se escriben. Si un tipo se especifica como void f(typename A::B, A) , el T en A::B no se escribe pero se deduce T en A . ]

La deducción funciona en la dirección de avance:

 template  void f(T); f(2); // can deduce int from T 

¿Por qué está pasando esto?

No funciona en la dirección hacia atrás (su ejemplo):

 template  void g(typename S::type); 

¿Es tan difícil de ver que los argumentos de la plantilla sean valores char e int?

La deducción de la plantilla puede hacer algunas cosas mágicas (Turing completas), pero no creo que esta sea una de ellas.

Puede usar algo como (no probado):

 template  void h(SA a1) { STATIC_ASSERT(same_type::type>::value); typedef typename SA::type A; ... } 

Usando su biblioteca de afirmación estática favorita (Boost tiene dos).