c++ - ¿Por qué se permite la especialización parcial de una plantilla de clase anidada, mientras que completa no?
templates metaprogramming (4)
Adivino por qué sucede esto: las especializaciones completas ya no son "clases / funciones de plantilla", son clases / métodos "reales" y llegan a tener símbolos reales (vinculables-visibles). Pero para una plantilla completamente especializada dentro de una parcialmente especializada, esto no sería cierto. Probablemente esta decisión fue tomada simplemente para simplificar la vida de los compiladores-escritores (y hacer la vida más difícil para los codificadores, en el proceso: P).
template<int x> struct A {
template<int y> struct B {};.
template<int y, int unused> struct C {};
};
template<int x> template<>
struct A<x>::B<x> {}; // error: enclosing class templates are not explicitly specialized
template<int x> template<int unused>
struct A<x>::C<x, unused> {}; // ok
Entonces, ¿por qué no se permite la especialización explícita de una clase (o función) anidada interna, si la clase externa no está especializada también? Por extraño que parezca, puedo evitar este comportamiento si solo especializo parcialmente la clase interna simplemente añadiendo un parámetro de plantilla ficticio. Hace las cosas más feas y más complejas, pero funciona.
Consideraría las especializaciones completas como un subconjunto de especializaciones parciales, especialmente porque puede expresar cada especialización completa como parcial con la adición de un parámetro ficticio. Entonces esta desambiguación entre especialización parcial y completa no tiene sentido para mí.
Desgraciadamente, nadie en comp.std.c ++ se atrevió a responder, así que lo vuelvo a poner aquí con una recompensa.
Nota: Necesito esta característica para plantillas recursivas de la clase interna para un conjunto de la clase externa y la especialización del parámetro interno depende del parámetro de la plantilla externa.
El estándar C ++ prohíbe explícitamente la especialización completa de las clases de plantilla de miembro en el primer caso. De acuerdo con 14.7.3 / 18:
En una declaración de especialización explícita para un miembro de una plantilla de clase o una plantilla de miembro que aparece en el ámbito de espacio de nombres, la plantilla de miembro y algunas de las plantillas de clase adjuntas pueden permanecer no especializadas, excepto que la declaración no debe especializar explícitamente una plantilla de miembro de clase si las plantillas de clases que lo incluyen tampoco están explícitamente especializadas .
Respaldando el argumento de Virgil (él fue más rápido que yo publicando el mismo razonamiento), considere esto:
template<typename T1>
class TOuter
{
public:
template<typename T2>
class TInner
{
public:
T1 m_1;
T2 m_2;
};
};
template<typename T1>
template<>
class TOuter<T1>::TInner<float>
{
public:
T1 m_1;
float m_2;
};
¿Tinter está completamente especializado o parcialmente especializado debido a T1?
Editar:
Después de considerar algunos de los otros comentarios, parece que desea tener una especialización completa basada en el parámetro de plantilla en la clase externa. Si anida la implementación de la clase interna, eso parece funcionar en Visual Studio 2005:
template<typename T1>
class TOuter
{
public:
template<typename T2>
class TInner
{
public:
std::string DoSomething() { return "Inner - general"; }
T2 m_2;
};
template<>
class TInner<T1>
{
public:
std::string DoSomething() { return "Inner - special"; }
T1 m_1;
};
};
TOuter :: TInner será la especialización de TInner. No pude lograr que compilara con la implementación fuera de la plantilla.
Sin embargo, puede evitar este comportamiento delegando el trabajo real en otra estructura:
namespace detail
{
template <class T, class U>
struct InnerImpl {};
}
template <class T>
struct Outer
{
template <class U>
struct Inner: detail::InnerImpl<T,U>
{
};
};
Ahora puedes especializar InnerImpl
como quieras