2010-01-05 23 views
10

Tengo una plantilla de clase anidada dentro de otra plantilla. Especializarlo parcialmente es fácil: acabo de declarar otro bloque template< … > dentro de su padre.especialice una plantilla de miembro sin especializar su padre

Sin embargo, necesito otra especialización parcial que sucede para especificar todos sus argumentos de plantilla local. Esto lo convierte en una especialización explícita. Las especializaciones explícitas, por la razón que sea, deben estar en el ámbito del espacio de nombres. Para declararlo fuera de su clase principal, el padre debe estar nominado, lo que requiere una lista de argumentos de plantilla no vacía. Esto implica una especialización parcial. La especialización parcial es lo que estoy haciendo, y se supone que debe funcionar en un alcance externo arbitrario. Pero tanto GCC como Comeau no identifican el parámetro de plantilla en la nominación principal con los argumentos formales de especialización parcial.

template< class X > struct A { 
    template< class Y > struct B; // initial declaration OK 

    template< class Z > 
    struct B< A<Z> > {}; // partial OK as long as there's a local arg 

    template<> // ERROR: this syntax triggers explicit specialization 
    struct B<int> {}; 
}; 

template<> // ERROR: can't nest template<>s here (why?) 
template< class X > // ERROR: can't deduce X from type of A<X>::B<int> (why?) 
struct A<X>::B<int> {}; 

(I dejado todo mi código de parada en; comentar de manera apropiada para tratar de tener sentido.)

+0

Por cierto, puede solucionarlo agregando un argumento ficticio, por ejemplo, un 'int' que siempre es' 0'. Esta es la primera vez que juego con C++ 0x; Estoy tratando de iterar sobre una 'tupla'. He hecho este tipo de cosas antes, y es molesto que la 'tupla' de C++ 0x sea menos poderosa que la de Boost ... iterar a través de argumentos de plantilla es una funcionalidad útil que no debe seguir siendo un rito de paso. Ah, y para todos mis problemas GCC todavía ICE una vez que corrijo todos los errores. – Potatoswatter

Respuesta

9

Es ilegal bajo C++ estándar 14.7.3/18:

.... la declaración no explícitamente especializar un miembro de la clase plantilla si sus plantillas de clase adjuntas tampoco están explícitamente especializadas .

+0

¡Gracias! Sé que he pasado por esto antes, porque se aplica a la recursión de todas las plantillas. – Potatoswatter

0

cosas complejas. Su código inicial ICE es VC10 Beta2, agradable.

En primer lugar, creo que tienes esto al revés:

template<> 
template< class X > 
struct A<X>::B<int> {}; 

X es un parámetro de plantilla a struct A, y B es un totalmente especializada, por lo que creo que debería ser esta:

template< class X > 
template<> 
struct A<X>::B<int> {}; 

Pero incluso esto no compila. El texto de error es realmente útil, sin embargo:

a.cpp a.cpp (11): error C3212: 'A :: B': una explícita especialización de un miembro de la plantilla debe ser un miembro de una explícita especialización a.cpp (8): véase la declaración de 'a :: B'

parece que sólo es legal para especializarse totalmente B si también se especializan totalmente A.

Editar: Ok, escuché de alguien que puede hablar con autoridad sobre esto - para parafrasear, este es un área muy turbia en el estándar, y es un problema abierto con el Comité C++ para limpiarlo ("es" que son especializaciones explícitas de miembros de las plantillas de clase). En el corto plazo, el consejo es "No hagas eso".

+0

Sí, noté que había publicado las listas de argumentos anidados "al revés"; Intenté en ambos sentidos hasta que me enfermé. Una forma en que no ve X y la otra forma en que se queja es explícita en el interior parcial. También dependiendo de qué compilador usó, por supuesto. El estándar es muy vago y desorganizado sobre esto, pero no veo ninguna razón por la que sea ilegal. – Potatoswatter

+0

Ya veo. No soy un abogado de idiomas (aunque a veces juego uno en los internets), pero VC10 es muy conforme, por lo que si me dice que algo es ilegal, tiendo a creerlo. Con suerte, alguien más puede saltar con el lenguaje que describe este comportamiento. –

0

Al menos esto funciona en VC 2010. Pero no puedo escribir la def. de fun() para "int" fuera de la declaración de clase. EDITAR: Lamentablemente, g ++ también tiene problemas de compilación. EDIT: El código siguiente trabajó en VC 2010.

template<typename X> 
class A 
{ 
public: 
    A() 
    { 

    } 

    template<typename Y> 
    struct B 
    { 
     void fun(); 
    }; 

    template<> 
    struct B<int> 
    { 
     void fun() 
     { 
      cout << "Specialized version called\n"; 
     } 
     //void fun(); 
    }; 



public: 

    B<X> b; 
}; 



template<typename X> 
template<typename Y> 
void A<X>::B<Y>::fun() 
{ 
    cout << "templated version called\n"; 
} 

int main() 
{ 
    A<int> a; 
    a.b.fun(); 
    A<float> a1; 
    a1.b.fun(); 
} 
+0

Eso es bueno saber. Diría que no hay una * buena * razón por la cual los compiladores no deberían apoyar esto si es que lo hacen. No quiero escribir la definición fuera de la clase, de todos modos. Pero, por supuesto, esto fue lo primero que intenté ... – Potatoswatter

4

Tiendo a no utilizar demasiadas clases anidadas. Mi principal queja es que tienen una tendencia a hinchar el código de la clase en la que están anidados.

por lo tanto, me gustaría proponer otra solución:

namespace detail 
{ 
    template <class X, class Z> class BImpl; 
    template <class X, class Z> class BImpl<X, A<Z> > {}; 
    template <class X> class BImpl<X,int> {}; 
} 

template <class X> 
class A 
{ 
    template <class Z> struct B: BImpl<X,Z> {}; 
}; 

Ten en cuenta que se requiere para pasar X como argumento para BImpl si alguna vez desea también se especializan A. ¡Lo curioso es que en este caso, termino con una especialización parcial!

+0

Sí. Mi preferencia es para las clases infladas en lugar de la representación externa inflada con 'friend's ... la cantidad total de código es la misma, o menos con la anidación. En este caso particular, la clase padre tenía una lista de parámetros variados C++ 0x y estaba tratando de pasar un subconjunto al niño, que por lo tanto también es variadic. Por lo tanto, no hay forma de pasar todos los argumentos de los padres al niño/amigo y, sin embargo, especializar explícitamente algún caso del niño/amigo. – Potatoswatter

Cuestiones relacionadas