template - typedef c++
Especialización de plantillas anidadas (7)
De acuerdo con estos mensajes:
http://www.cpptalk.net/template-member-function-specialization-vt11666.html
no puede especializar los miembros de la plantilla de una clase de plantilla sin especializar la clase externa. No citan verso y capítulo. Mi copia de "The C ++ Programming Language" no revela nada inmediatamente, y mi copia del estándar está en mi casa (mi copia de seguridad, más conocida aquí como "Chris" tampoco está :-)
Tener un pedo cerebral ... ¿Es posible hacer algo como esto?
template<int a> struct Foo
{
template<int b> struct Bar;
};
template<int a> struct Foo<a>::Bar<1> //Trying to specialize Bar
{
};
No tengo que hacer esto, pero me permitirá ocultar algunos detalles de implementación desde el ámbito del espacio de nombres.
Sugerencias apreciadas!
PD: Olvidé mencionar que el lenguaje no admite la especialización explícita de Bar en el alcance de Foo. AFAICS, de todos modos.
No puedes hacer eso. He intentado muchas variaciones. Esto , sin embargo, se compila en GCC 4.1:
template<int a> struct Foo
{
template<int b> struct Bar;
template<1> struct Bar;
};
Editar (después de revisar el estándar): si se proporciona un, puede hacer esto:
template <> template <> Foo<1> Bar<1>;
Pero no si Foo no está especializado primero.
Sí tu puedes. Pero necesitarás cambiar la estructura de la llamada, pero solo un poco.
Específicamente, use el patrón de estrategia para reestructurar la implementación de la función miembro como una clase (que se permite que sea especializada).
Esto está permitido siempre que la clase de estrategia no esté anidada (y, por lo tanto, no dependa del tipo de plantilla no especializada).
ej. (esto probablemente no es sintácticamente correcto, pero la idea debería ser clara)
template <class T>
class OuterThingThatIsNotSpecialized
{
template <class U>
void memberWeWantToSpecialize(const U& someObj_)
{
SpecializedStrategy<U>::doStuff(someObj_);
}
};
template <class U>
struct SpecializedStrategy;
template <>
SpecializedStrategy<int>
{
void doStuff(const int&)
{
// int impl
}
};
template <>
SpecializedStrategy<SomeOtherType>
{
void doStuff(const SomeOtherType&)
{
// SOT impl
}
};
Esto es increíblemente útil porque las llamadas a OuterThingThatIsNotSpecialized para los tipos donde no existe implementación simplemente no se compilarán.
PD. Incluso puede usar esta estrategia para especializar parcialmente las funciones de la plantilla, algo que de otro modo sería una imposibilidad de C ++.
Como explicaron los carteles anteriores, esto no es posible. Sin embargo, puede mover la plantilla anidada a una clase base que no sea de plantilla:
struct FooBase
{
template<int b> struct Bar;
}
template<int a> struct Foo : public FooBase
{
};
struct FooBase::Bar<1> // specializing Bar
{
};
Como han señalado otros, C ++ no le permite especializar una clase anidada si la plantilla de la clase externa tampoco está especializada. Cuando tuve una situación así, pude solucionarlo con una clase de ayuda metida en un espacio de nombres interno:
namespace internal {
template <int a, int b> struct FooBarHelper
{ /* ... */ };
// Specialization
template <int a> struct FooBarHelper<a, 1>
{ /* specialized version goes here */ };
}
template<int a> struct Foo
{
template<int b> struct Bar : public internal::FooBarHelper<a, b>;
};
Por supuesto, no está tan oculto como te gustaría que fuera.
Esto es lo que he estado haciendo, que creo que es más simple / más en línea con lo que estás tratando de hacer:
Con Helper
template<int a> struct Foo
{
template<int, int> struct Bar__;
template<int b> using Bar = Bar__<b, b>;
};
template<int a> template<int b, int c> struct Foo<a>::Bar__
{
// general case
const static int x = 0;
};
template<int a> template<int b> struct Foo<a>::Bar__<b, 1>
{
const static int x = 1;
};
int main(int argc, const char * argv[])
{
std::cout << Foo<1>::Bar<0>::x << "/r/n"; // general case - output 0
std::cout << Foo<1>::Bar<1>::x << "/r/n"; // specialized case - output 1
return 0;
}
O bien, el ayudante se puede quitar si no te importa doblar la especialización cada vez:
Sin ayuda
template<int a> struct Foo
{
template<int b, int c> struct Bar;
};
template<int a> template<int b, int c> struct Foo<a>::Bar
{
// general case
const static int x = 0;
};
template<int a> template<int b> struct Foo<a>::Bar<b, 1>
{
const static int x = 1;
};
int main(int argc, const char * argv[])
{
std::cout << Foo<1>::Bar<0, 0>::x << "/r/n"; // general case - output 0
std::cout << Foo<1>::Bar<1, 1>::x << "/r/n"; // specialized case - output 1
return 0;
}
La cláusula 18, sección 14.7.3 de la norma de 1998 (ISO14882: 1998) dice que la especialización explícita de las clases de miembros de la plantilla (interna) no está permitida cuando la clase de la plantilla (externa) no está explícitamente especializada.