He estado jugando con el sonido metálico de un tiempo, y me topé con «test/SemaTemplate/dependent-template-recover.cpp» (en el ruido de la distribución), que se supone para proporcionar sugerencias para recuperarse de una plantilla de error.

Todo esto puede ser fácilmente reducida a un mínimo ejemplo:

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 tengo un tiempo difícil entender de dónde exactamente se supone que uno debe insertar el template palabra clave para que el código sea sintácticamente correcta?

  • Intenta insertarlo donde la flecha está señalando?
  • Similar a this y este
InformationsquelleAutor | 2010-09-24

4 Comentarios

  1. 83

    ISO C++03 14.2/4:

    Cuando el nombre de un miembro de la plantilla de especialización aparece después . o -> en un postfix-expresión, o después de la nested-nombre-especificador de un calificado-id, y el postfix-expresión o calificado-id explícitamente depende de una plantilla de parámetros (14.6.2), el miembro nombre de la plantilla debe ser precedida por la palabra clave template. De lo contrario, el nombre se supone que el nombre de un no-plantilla.

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

    Para cambiar t->f0<U>() a t->template f0<U>().

    • Curiosamente, he pensado poner la expresión en paréntesis: t->(f0<U>()) habría fijado que, como yo pensaba que iba a poner f0<U>() en independiente expresión… bien, pensé mal, parece…
    • Podría tal vez hacer comentarios sobre por qué este es el caso? ¿Por qué C++ requieren este tipo de sintaxis?
  2. 23

    Además de los puntos que otros hicieron, aviso que a veces el compilador no podía hacer en su mente y ambas interpretaciones pueden producir alternativa válida programas al crear instancias de

    #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 la omisión de template antes de f<int()> pero 1 al insertarla. Os dejo como ejercicio para averiguar lo que hace el código.

    • Ahora que es un diabólico ejemplo!
    • Yo no puedo reproducir el comportamiento que describes en Visual Studio 2013. Siempre llama f<U> y siempre imprime 1, lo que hace perfecto sentido para mí. Todavía no entiendo por qué la template palabra clave es necesaria y qué diferencia hace.
    • el VSC++ compilador no es compatible con el compilador de C++. Una nueva pregunta es necesario si usted quiere saber por qué VSC++ imprime siempre 1.
    • Esta respuesta se explica por qué template es necesario: stackoverflow.com/questions/610245/… sin tener que depender exclusivamente de standardese términos que son difíciles de entender. Por favor, informe si hay algo en que la respuesta es todavía confuso.
    • Gracias, una gran respuesta. Resulta que me lo he leído antes porque ya estaba upvoted por mí. Al parecer, mi memoria es meh.
  3. 10

    Insertar justo antes del punto donde el símbolo de intercalación:

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

    Edit: la razón de esta norma se hace más claro si usted piensa como un compilador. Compiladores generalmente sólo mirar hacia adelante uno o dos fichas a la vez, y generalmente no «mirar hacia adelante» para el resto de la expresión.[Editar: véase el comentario] la razón por La que la palabra clave es la misma razón por la que necesita el typename palabra clave para indicar dependiente del tipo de nombres: es decirle al compilador de «hey, el identificador que estás a punto de ver es el nombre de una plantilla, en lugar de el nombre de un miembro de datos estáticos seguido por un signo menor que».

    • Me gustaría tener nunca ha sido capaz de adivinar que… pero gracias ;-). es evidente que hay siempre algo que aprender acerca de C++!
    • Incluso con infinito look-ahead, usted todavía tendrá template. Hay casos en que ambas con y sin template producirá programas válidos con un comportamiento diferente. Así que esto no es sólo un sintáctica del problema (t->f0<int()>(0) es válido sintácticamente tanto para el menor que y el argumento de plantilla de la lista de la versión).
    • Schaub – litb: a la Derecha, así que es más un problema de asignación coherente de significado semántico de la expresión, que es de mirar hacia delante.
  4. 8

    Extracto de Las Plantillas De C++

    El .Construcción de plantilla
    Una muy similar problema fue descubierto después de la introducción de typename. Considere el siguiente ejemplo, utilizando el estándar bitset tipo:

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

    La extraña construcción en este ejemplo .de la plantilla. Sin ese extra de uso de la plantilla, el compilador no sabe que el menor-que token (<) que sigue no es realmente «menos que», sino el principio de una plantilla de lista de argumentos. Tenga en cuenta que este es un problema sólo si la construcción antes de que el periodo depende de un parámetro de plantilla. En nuestro ejemplo, el parámetro bs depende del parámetro de plantilla N.

    En conclusión, la .plantilla de la notación (y similares anotaciones tales como:- >plantilla) debe ser utilizado sólo en el interior de las plantillas y sólo si siguen algo que depende de un parámetro de plantilla.

    • de hecho, +1 por el excelente ejemplo

Dejar respuesta

Please enter your comment!
Please enter your name here