2009-11-05 17 views
21

Este es un caso de prueba mínima de un código que realmente tengo. Se produce un error cuando se trata de evaluar a.getResult<B>():función de plantilla no juegan bien con la función de miembro de la plantilla de clase

test.cpp: In function 'void printStuff(const A&)': 
test.cpp:6: error: expected primary-expression before '>' token 
test.cpp:6: error: expected primary-expression before ')' token 

El código es:

#include <iostream> 

template< class A, class B> 
void printStuff(const A& a) 
{ 
    size_t value = a.getResult<B>(); 
    std::cout << value << std::endl; 
} 

struct Firstclass { 
    template< class X > 
    size_t getResult() const { 
     X someInstance; 
     return sizeof(someInstance); 
    } 
}; 

int main(int, char**) { 
    Firstclass foo; 

    printStuff<Firstclass, short int>(foo); 
    printStuff<Firstclass, double>(foo); 

    std::cout << foo.getResult<double>() << std::endl; 

    return 0; 
} 

Si comento a cabo la función printStuff y donde se llama, la llamada foo.getResult<double>() compila bien y hace lo que se espera.

Alguna idea de lo que está pasando? He estado trabajando con código extensivamente templado por un tiempo y nunca he encontrado algo como esto.

Respuesta

35

Cuando se hace referencia a una plantilla que es un miembro de tipo dependiente, usted tiene que anteponer con una palabra clave template. Así es como la llamada a getResult dentro printStuff debe mirar

size_t value = a.template getResult<B>(); 

Esto es similar al uso de la palabra clave typename cuando se hace referencia a typenames anidados en un tipo dependiente. Por alguna razón, lo de typename con tipos anidados es bastante conocido, pero el requisito similar para template con plantillas anidadas es relativamente desconocida.

Tenga en cuenta que la estructura general de sintaxis es un poco diferente, sin embargo. El typename siempre se pone delante del nombre completo del tipo, mientras que template se inserta en el medio.

Una vez más, esto sólo es necesario cuando se está accediendo a un miembro de la plantilla de un tipo dependiente, que en el ejemplo anterior sería A en printStuff. Cuando llama al foo.getResult<> en main, el tipo de foo no es dependiente, por lo que no es necesario incluir la palabra clave template.

+7

Wow, acabo cuando pensaba que sabía todo lo que había que saber sobre C++ ... –

+6

Gracias! Esa es la sintaxis más extraña que he visto en C++. –

+3

De alguna manera, VC++ es bastante indulgente al respecto (es decir, a menudo puedes salirte con la tuya), ¡pero definitivamente no es así! –

8

Su código está mal formada de acuerdo a C++ estándar 14.2/4:

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

Por lo tanto, usted debe escribir size_t value = a.template getResult<B>();

Cuestiones relacionadas