2012-10-10 46 views
6

Este es el escenario:¿Cómo me refiero a una plantilla de clase, como plantilla, desde dentro de su propia definición de clase?

template <template <typename> class T, typename V> 
struct parent { 
    void do_something(); 
}; 

template <typename V> 
struct child : public parent<child, V> { 
    void do_something(V argument); 
    using parent<child, V>::do_something; // C3200: invalid template argument for template parameter 'IMPL', expected a class template 
}; 

El código anterior falla al compilar en la línea determinada por el error dado (MSVC 9,0). Sin embargo si escribo esto en su lugar, fuera de la definición de clase para child:

template <typename V> 
struct parent_identity_meta { 
    typedef typename parent<child, V> type; // no error! 
}; 

ahora puedo hacerlo con éxito el siguiente, dentro de child:

using parent_identity_meta<V>::type::do_something; 

Sé que hay una limitación (aliviado en C + +11) que no puede tipear def contra una plantilla, pero no creo que sea eso con lo que me estoy encontrando aquí, de lo contrario fallaría el typedef en parent_identity_meta. Parece que child se refiere a la plantilla cuando no está dentro de su propia definición de clase, y a la clase que se genera desde sí mismo.

Esto es bastante comprensible (tener que escribir child<V> cada vez sería doloroso); pero ¿hay alguna manera de anular este comportamiento?

+1

¿Has probado ':: child'? –

+0

No puedo explicar el mensaje de error, pero noté que 'do_something' es privado. Creo que eso también es un problema. – jogojapan

+0

@SethCarnegie: Eso lo arregla para mí. Aunque no estoy seguro de por qué. Ooh, en realidad creo que lo entiendo (: – Mankarse

Respuesta

5

Este es un lugar donde C++ 03 y C++ 11 son diferentes entre sí. La parte relevante de la norma es [temp.local]/1. En C++ 03, esto indica:

Como las clases normales (sin plantilla), las plantillas de clase tienen un nombre de clase inyectado (cláusula 9). El nombre de clase inyectado se puede usar con o sin una lista de argumento de plantilla. Cuando se utiliza sin una lista de argumento de plantilla, es equivalente al nombre de clase inyectado seguido de los parámetros de plantilla de la plantilla de clase incluida en <>. Cuando se utiliza con una plantilla-argumento-lista, se refiere a la especialización de plantilla de clase especificada, que podría ser la especialización actual u otra especialización.

Esto significa que child (sin ningún tipo de argumentos de plantilla) se refiere a la especialización child<V>. En C++ 11, se cambió a:

Al igual que las clases normales (sin plantilla), las plantillas de clase tienen un nombre de clase inyectado (Cláusula 9). El nombre de clase inyectado se puede usar como un nombre de plantilla o un nombre de tipo. Cuando se usa con una plantilla-argumento-lista, como un argumento-plantilla para una plantilla-parámetro-plantilla, o como el identificador final en el especificador-tipo-elaborado de una declaración de plantilla de clase amiga, se refiere a la plantilla de clase misma . De lo contrario, es equivalente al nombre de la plantilla seguido de los parámetros de plantilla de la plantilla de clase incluida en <>.

Nota en particular When it is used ... as a template-argument for a template template-parameter ... it refers to the class template itself.. Esto significa que en C++ 11, su código sería correcto.

+0

Ah, vencerme por unos segundos :) –

+0

Muchas gracias por la referencia y la información de C++ 11. MSVC9 no hace C++ 11, MSVC10 hace algo de eso. Cambio de un lado a otro - Probablemente hice esto en MSVC10 y no me di cuenta de que no funcionó. –

+0

Jaja, gracias @SethCarnegie ... Iba a votarte el tuyo ya que, realmente, llegaste a la respuesta primero :) Gracias a los dos. –

Cuestiones relacionadas