2010-02-28 24 views
6

Quiero tener una clase de plantilla que se parece a lo que tengo abajo. Luego, quiero una función en ella con una especialización de plantilla que depende de un parámetro de plantilla CLASE. ¿Cómo hago que esto funcione? Me doy cuenta de que el código que proporcioné está mal en muchos niveles, pero es solo para ilustrar el concepto.Clase de plantilla, especialización de funciones

template <typename _T, size_t num> 
class Foo 
{ 
    // If num == 1, I want to call this function... 
    void Func<_T, 1>() 
    { 
     printf("Hi!"); 
    } 

    // Otherwise, I want to call this version. 
    void Func<_T, num>() 
    { 
     printf("Hello world!"); 
    } 
}; 

Respuesta

9
struct Otherwise { }; 
template<size_t> struct C : Otherwise { }; 

// don't use _Uppercase - those names are reserved for the implementation 
// (i removed the '_' char) 
template <typename T, size_t num> 
class Foo 
{ 
public: 
    void Func() { Func(C<num>()); } 

private: 
    // If num == 1, I want to call this function... 
    void Func(C<1>) 
    { 
     printf("Hi 1!"); 
    } 

    // If num == 2, I want to call this function... 
    void Func(C<2>) 
    { 
     printf("Hi 2!"); 
    } 

    // Otherwise, I want to call this version. 
    void Func(Otherwise) 
    { 
     printf("Hello world!"); 
    } 

    //// alternative otherwise solution: 
    // template<size_t I> 
    // void Func(C<I>) { .. } 
}; 
+0

Me gusta esta solución. ¡Incluso aprendí algo sobre la convención de nombres de C++! Sin embargo, ¿cómo hago esto si tengo, por ejemplo, cualquier cantidad de especializaciones para varios valores de num junto con un retroceso en caso de que ninguno de ellos funcione? –

+0

@wowus, respuesta actualizada –

+0

Gracias, aceptada. –

2

No hay especializaciones parcial de la función plantillas, y se especializan en parte un miembro de lo que necesita primero especializarse en parte la plantilla de clase.

template< typename _T, size_t num > 
struct Foo { 
    void Func() { 
     printf("Hello world!"); 
    } 
}; 

template< typename _T > 
struct Foo< _T, 1 > { 
    void Func() { 
     printf("Hi!"); 
    } 
}; 

Ahora, si Foo también contiene métodos distintos de Func cuya aplicación es independiente del valor de num, y que no quieren duplicar su aplicación en la especialización de Foo, se puede aplicar el siguiente patrón:

template< typename _T, size_t num > 
struct FooFuncBase { 
    void Func() { 
     printf("Hello world!"); 
    } 
}; 

template< typename _T > 
struct FooFuncBase< _T, 1 > { 
    void Func() { 
     printf("Hi!"); 
    } 
}; 

template< typename _T, size_t num > 
struct Foo : public FooFuncBase< _T, num > { 
    void OtherFuncWhoseImplementationDoesNotDependOnNum() { 
    ... 
    } 
}; 

O, usando CRTP:

template< typename _Derived, typename _T, size_t num > 
struct FooFuncBase { 
    void Func() { 
     static_cast< _Derived* >(this)->OtherFuncWhoseImplementationDoesNotDependOnNum(); 
     printf("Hello world!"); 
    } 
}; 

template< typename _Derived, typename _T > 
struct FooFuncBase< _Derived, _T, 1 > { 
    void Func() { 
     static_cast< _Derived* >(this)->OtherFuncWhoseImplementationDoesNotDependOnNum(); 
     printf("Hi!"); 
    } 
}; 

template< typename _T, size_t num > 
struct Foo : public FooFuncBase< Foo< _T, num >, _T, num > { 
    void OtherFuncWhoseImplementationDoesNotDependOnNum() { 
    printf("Other"); 
    } 
}; 
+0

que es una clase que se está especializada en este caso, el PO no sabe cómo escribir la sintaxis para que lo pienso. –

+1

Creo que hay más, veamos qué contesta. Estoy casi seguro de que solo necesita especializar un subconjunto de métodos de 'Foo', no toda la clase. – vladr

+0

Me gusta la solución, pero creo que es bastante harto poner el "código de caso especial" en la interfaz pública y todo el código general en la base. Sin duda hay una mejor manera! –

1

Esto se llama especialización de plantilla parcial. Se ve así:

template<typename _T, size_t num> 
class FooBase 
{ 
}; 

template <typename _T, size_t num> 
class Foo : public FooBase<_T,num> 
{ 
    void Func() 
    { 
     printf("Hello world!"); 
    } 
}; 


template <typename _T> 
class Foo<_T,1> : public FooBase<_T,num> 
{ 
    void Func() 
    { 
     printf("Hi!"); 
    } 
} 
+0

No quiero duplicar todo el cuerpo de Foo (hay muchos otros métodos que he omitido) en cada especialización. –

+0

Editado para permitir funciones en una clase base. –

Cuestiones relacionadas