Error de plantilla confuso


He estado jugando con clang un tiempo, y me topé con "test/SemaTemplate/dependent-template-recover.cpp " (en la distribución clang) que se supone que proporciona pistas para recuperarse de un error de plantilla.

Todo se puede reducir fácilmente a un ejemplo mínimo:

template<typename T, typename U, int N> struct X {
    void f(T* t)
    {
        // expected-error{{use 'template' keyword to treat 'f0' as a dependent template name}}
        t->f0<U>();
    }
};

El mensaje de error producido por clang:

tpl.cpp:6:13: error: use 'template' keyword to treat 'f0' as a dependent template name
         t->f0<U>();
            ^
            template 
1 error generated.

... Pero me cuesta entender dónde exactamente se supone que se debe insertar la palabra clave template para tener el código que debe ser ¿sintácticamente correcto?

Author: Prasoon Saurav, 2010-09-24

4 answers

ISO C++03 14.2/4:

Cuando el nombre de una especialización de plantilla de miembro aparece después . or - > in a postfix-expression, or after anided-name-specifier in a qualified-id, and the postfix-expression or qualified-id explicitly depends on a template-parameter (14.6.2), the member template name must be prefijed by the keyword template. De lo contrario, se asume que el nombre nombra a una no plantilla.

En t->f0<U>(); f0<U> es una especialización de plantilla de miembro que aparece después de -> y que depende explícitamente del parámetro de plantilla U, por lo que la especialización de plantilla miembro debe ir precedida por la palabra clave template.

Así que cambia t->f0<U>() a t->template f0<U>().

 69
Author: Prasoon Saurav,
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-08-02 13:48:33

Además de los puntos que otros hicieron, tenga en cuenta que a veces el compilador no podía tomar una decisión y ambas interpretaciones pueden producir programas válidos alternativos al instanciar

#include <iostream>

template<typename T>
struct A {
  typedef int R();

  template<typename U>
  static U *f(int) { 
    return 0; 
  }

  static int f() { 
    return 0;
  }
};

template<typename T>
bool g() {
  A<T> a;
  return !(typename A<T>::R*)a.f<int()>(0);
}


int main() {
  std::cout << g<void>() << std::endl;
}

Esto imprime 0 cuando se omite template antes de f<int()> pero 1 cuando se inserta. Lo dejo como un ejercicio para averiguar qué hace el código.

 20
Author: Johannes Schaub - litb,
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
2010-09-24 12:22:26

Introdúzcalo justo antes del punto donde está el recuadro:

template<typename T, typename U, int N> struct X {
     void f(T* t)
     {
        t->template f0<U>();
     }
};

Editar: la razón de esta regla se vuelve más clara si piensas como un compilador. Los compiladores generalmente solo miran hacia adelante uno o dos tokens a la vez, y generalmente no "miran hacia adelante" al resto de la expresión.[Editar: ver comentario] La razón de la palabra clave es la misma que la razón por la que necesita la palabra clave typename para indicar nombres de tipo dependientes: le dice al compilador "oye, el identificador que estás a punto de ver es el nombre de una plantilla, en lugar del nombre de un miembro de datos estático seguido de un signo menos que".

 9
Author: Doug,
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
2010-09-24 11:34:14

Extracto de Plantillas C++

El.construcción de plantilla Un problema muy similar fue descubierto después de la introducción de typename. Considere el siguiente ejemplo usando el tipo estándar de bitset:

template<int N> 
void printBitset (std::bitset<N> const& bs) 
{ 
    std::cout << bs.template to_string<char,char_traits<char>, 
                                       allocator<char> >(); 
} 

La construcción extraña en este ejemplo es .plantilla. Sin ese uso adicional de template, el compilador no sabe que el token menos que (

En conclusión, el .la notación de plantilla (y notaciones similares como ->template) debe usarse solo dentro de las plantillas y solo si siguen algo que depende de un parámetro de plantilla.

 6
Author: Chubsdad,
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
2010-09-24 11:11:58