2011-05-24 23 views
6

Estoy jugando con plantillas y especialización parcial, pero hay una especialización que no sé cómo escribir ... Simplificaré el código para facilitar la lectura.Especialización parcial con el tipo anidado en una clase con plantilla

condiser Vamos

template <typename T> 
    class x 
{ 
    ... 
}; 

Por lo general, puedo especializar así:

class x<a_type> 
{ 
    ... 
}; 

También funciona con tipos de plantillas:

template <typename T> 
    class x<std::vector<T>> 
{ 
    ... 
} 

Ahora me gustaría hacer la especialización de un tipo anidado en una clase con plantilla:

template <typename T> 
    class y 
{ 
    struct nested_type 
    { 
     y a_member; 
    }; 

    ... 
}; 

// Here comes the specialization 

template <typename T> 
    class x<y<T>::nested_type> 
{ 
    ... 
}; 

Esto falla. También traté de poner 'typename' antes de y :: nested_type pero no resolvió el problema. El error del compilador es:

type/value mismatch at argument 1 in template parameter list for ‘template <class T> struct x’ 

Lo que quiero hacer parece lógico, pero no estoy seguro de si es posible. Estoy usando C++ 0x con g ++ - 4.5. ¿Alguien sabe la sintaxis correcta para escribir tal especialización?

+0

Creo que necesitas editar la pregunta. Debe ser 'clase x <....>', no 'clase <....>' en los primeros dos bloques. ¿Seguro que has escrito cuidadosamente _todo_? –

+0

Sí, tienes razón. Eso es solo un pequeño error en mi mensaje, ya que no copié mi código pero preferí usar 'x' o' y' para simplificar el problema. Probé con ejemplos más pequeños, pero la respuesta de Mikael parece buena: no pude hacer un pequeño ejemplo de trabajo, y créanme, ¡probé muchas cosas! – neodelphi

+0

Tenga en cuenta que obtendrá un mensaje de error más sensible de GCC si utiliza la sintaxis "correcta", 'plantilla clase x :: tipo_animado>' en lugar de 'plantilla clase x :: tipo_anatizado>' (agregado 'typename'). – ildjarn

Respuesta

5

La respuesta es que usted no puede hacer esta especialización. No es un error de sintaxis, sino simplemente algo que no se puede realizar. Debes ver las especializaciones de las plantillas un poco como la sobrecarga de funciones. El compilador debe tomar el argumento de tipo en el sitio de uso, ver las especializaciones disponibles, buscar coincidencias y seleccionar la mejor (la más especializada). El problema con su ejemplo es que el paso "buscar coincidencias" no se puede realizar con dicha especialización. El compilador puede esperar que "tipo_anidado" sea cualquier cosa, no necesariamente un tipo único (como lo es en su ejemplo), sino que también podría ser un tipodef anidado, por ejemplo. Además, el compilador no puede predecir que ya está viendo todas las especializaciones de la plantilla "y", por lo que aunque tipo_incrustado sea un tipo único anidado en y (plantilla general), podría ser un typedef anidado en una próxima declaración de especialización de plantilla para la plantilla "y".

Al igual que con la sobrecarga de funciones y el algoritmo de coincidencia utilizado allí, el compilador tiene una capacidad limitada para deducir el tipo, y lo que limita es la cantidad de suposiciones que puede hacer. Si tiene una especialización para x<int> y luego usa x<int>, la coincidencia es trivial, no se necesitan deducciones, no se necesitan suposiciones. Si tiene una especialización como x<T*> y luego utiliza x<int*>, la coincidencia es fácil, se puede deducir que T es int. Si tiene una especialización como x< y<T>::type > y luego usa cualquier versión de x, ¿cómo se supone que el compilador debe deducir T de y :: tipo? Tendría que sustituir a T en todos los tipos posibles que existen en todo el mundo para ver si hay uno que resulte en un tipo anidado coincidente. Esa es una expectativa irracional, y es por eso que las capacidades de deducción tipo de las plantillas de C++ se detienen aquí. Muy a menudo, para saber si debe esperar que el compilador resuelva algo, simplemente póngase en su lugar y vea si es remotamente posible (la respuesta suele ser clara).

+0

Bueno, pensé que si usa 'x :: type>' por ejemplo, el compilador podría deducir 'y :: type' y luego encontraría la especialización correcta de' x'. Lo que dices tiene sentido, entiendo que el compilador no puede deducir 'T' de' x :: type> ', sin embargo, en mi caso,' T' se indica para que 'y :: type' pueda deducirse, lo que permite la resolución de especialización. Como solución alternativa, declararé mi estructura anidada fuera de la clase. Gracias por su respuesta. – neodelphi

+0

Sí, claro, el problema no está en el caso de uso previsto (por ejemplo, 'x < y :: tipo>'), es con cada otro caso de uso que deba verificarse contra esa especialización para determinar si puede combinarse y verificando esa coincidencia es imposible debido a tener que considerar una cantidad infinita de casos o tener que hacer suposiciones irrazonables (suponiendo que 'y :: type' nunca es un typedef para un tipo" no relacionado "a y ). –

Cuestiones relacionadas