2009-02-20 9 views
23

Tener un pedo en el cerebro ... ¿Es posible hacer algo como esto?Especialización en plantillas anidadas

template<int a> struct Foo 
{ 
    template<int b> struct Bar; 
}; 

template<int a> struct Foo<a>::Bar<1> //Trying to specialize Bar 
{ 
}; 

yo no tienen que hacer esto, pero me permitirá ocultar muy bien algunos detalles de implementación del ámbito de aplicación de espacio de nombres.

¡Sugerencias apreciadas!

P.S .: Olvidé mencionar que explícitamente la especialización para Bar dentro del alcance de Foo no es compatible con el idioma. AFAICS, de todos modos.

Respuesta

3

De acuerdo con estos mensajes:

http://www.cpptalk.net/template-member-function-specialization-vt11666.html

no se puede especializar los miembros de la plantilla de una clase de plantilla, sin que se especializa la clase exterior. No citan verso y capítulo. Mi copia de "El lenguaje de programación C++" no revela nada inmediatamente, y mi copia del estándar está en mi casa (mi copia de seguridad, mejor conocida aquí como "Chris" tampoco está :-)

+0

Decepcionante. ¡Gracias por la referencia, sin embargo! –

+0

ISO14882: 1998 La sección 14.7.3, párrafo 16 es la que describe esta situación. – greyfade

0

Puedes ' hacer eso He intentado muchas variaciones. Este, sin embargo, compila en GCC 4.1:

template<int a> struct Foo 
{ 
    template<int b> struct Bar; 
    template<1> struct Bar; 
}; 

Editar (después de la revisión de la norma): Si una se da, sin embargo, usted puede hacer esto:

template <> template <> Foo<1> Bar<1>; 

Pero no si Foo no está primero especializado.

12

Sí, puedes. Pero necesitarás cambiar la estructura de la llamada, pero solo un poco.

Específicamente, utilice el patrón de estrategia para reestructurar la implementación de la función de miembro como una clase (que se permite para ser especializada).

Esto está permitido siempre que la clase de estrategia no esté anidada (y, por lo tanto, no depende del tipo de plantilla no especializada).

p. Ej. (Esto probablemente no es sintácticamente correcta, pero la idea debe ser claro)

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 muy útil porque las llamadas a OuterThingThatIsNotSpecialized para tipos que no existe ninguna aplicación simplemente dejar de compilación.

PS. Incluso puede usar esta estrategia para especializar parcialmente las funciones de la plantilla, algo que de otro modo sería una imposibilidad de C++.

+0

tenga en cuenta que tiene una clase de plantilla de miembro y no una función de plantilla de miembro. la cosa es más complicada para una clase de plantilla de miembro. porque, por ejemplo, la amistad ya no se concede. –

11

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 plantilla (externa) no está explícitamente especializada.

0

Como explicaron los carteles anteriores, esto no es posible. Sin embargo, puede mover la plantilla anidada en una clase base no molde:

struct FooBase 
{ 
    template<int b> struct Bar; 
} 
template<int a> struct Foo : public FooBase 
{ 
}; 

struct FooBase::Bar<1> // specializing Bar 
{ 
}; 
0

Como otros han señalado, C++ no permite que usted se especializa una clase anidada si la plantilla de clase externa no está también especializada.Cuando tuve una situación como esa, yo era capaz de trabajar alrededor de ella con una clase de ayuda escondido 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 que no es tan oculto como le gustaría que fuera.

1

Esto es lo que he estado haciendo, que creo que es más simple/más en línea con lo que estamos tratando de hacer:

Con ayudante

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 - El ayudante puede eliminarse 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; 
} 
Cuestiones relacionadas