2010-09-22 29 views
6

¡Hola!C++ especialización de plantilla única con múltiples parámetros de plantilla

Me gustaría especializar solo uno de los dos tipos de plantillas. P.ej. template <typename A, typename B> class X debe tener una implementación especial para una sola función X<float, sometype>::someFunc().

Código de ejemplo:

main.h:

#include <iostream> 

template <typename F, typename I> 
class B 
{ 
public: 
    void someFunc() 
    { 
     std::cout << "normal" << std::endl; 
    }; 

    void someFuncNotSpecial() 
    { 
     std::cout << "normal" << std::endl; 
    }; 
}; 

template <typename I> 
void B<float, I>::someFunc(); 

main.cpp:

#include <iostream> 
#include "main.h" 

using namespace std; 

template <typename I> 
void B<float, I>::someFunc() 
{ 
    cout << "special" << endl; 
} 

int main(int argc, char *argv[]) 
{ 
    B<int, int> b1; 
    b1.someFunc(); 
    b1.someFuncNotSpecial(); 

    B<float, int> b2; 
    b2.someFunc(); 
    b2.someFuncNotSpecial(); 
} 

compilación falla por class B. ¿Es cierto que esto no es posible en C++ de esta manera? ¿Cuál sería la mejor solución?

[editar]

template <float, typename I> void B<float, I>::someFunc(); conduce a main.h: 26: error: 'flotar' no es un tipo válido para un parámetro constante plantilla

template <typename I> void B<float, I>::someFunc(); conduce a main.h: 27: error: uso no válido del tipo incompleto 'clase B'

Y estoy usando gcc.

[editar]

no quiero especializar a toda la clase, ya que hay otras funciones que no tienen una especialización.

+0

¿La plantilla de clase A está relacionada con su pregunta? – Doug

+0

Pensé que haría la pregunta más fácil de entender. Lo eliminaré. – tauran

+0

Esto se ha preguntado cientos de veces en stackoverflow :) Creo que algunos de nosotros podríamos configurar una plantilla real de preguntas frecuentes con tales preguntas. La gente puede consultar las preguntas frecuentes para ver si su pregunta es respondida, en lugar de tener que buscar a un imbécil. –

Respuesta

16

usted tiene que proporcionar una especialización parcial de la plantilla de clase B:

template <typename I> 
class B<float, I> 
{ 
public: 
    void someFunc(); 
}; 

template <typename I> 
void B<float, I>::someFunc() 
{ 
    ... 
} 

Usted también puede simplemente definir someFunc dentro de la especialización.

Sin embargo, si solo desea especializar una función, y no una clase, haga e. gramo.

template <typename F, typename I> 
void someFunc(F f, I i) { someFuncImpl::act(f, i); } 

template <typename F, typename I> 
struct someFuncImpl { static void act(F f, I i) { ... } }; 

// Partial specialization 
template <typename I> 
struct someFuncImpl<float, I> { static void act(float f, I i) { ... } }; 

Pero no puede especializar una plantilla de función sin este truco.

+1

No podría saber esto. Pero en mi caso de uso hay muchas otras funciones que no tienen especialización. Con este enfoque, debería duplicar todas estas funciones. – tauran

+1

@tauran: no puede proporcionar especializaciones parciales para plantillas de funciones. Solo para plantillas de clase, y debe proporcionar la definición nuevamente para toda la clase. Vive con él, o mira la respuesta actualizada. –

+0

¿Podría abordar una cosa más en el código de tauran? Hay 'template void B :: someFunc();' al final de 'main.h'. Creo que tauran quiere declarar, que hay una especialización definida en alguna parte, en otra unidad de compilación. ¿Tal cosa no requiere plantillas exportadas? Si se trata de la especialización, para ser visible en todas las unidades de compilación, 'main.h' está incluido, ¿no tiene que estar en el encabezado? –

5

Although you can totally specialize member functions of a class template, you cannot _partially specialize member functions. - Andrei Alexandrescu

parcial Clase especialización se explica por los otros carteles.

Puede, sin embargo, el uso de la sobrecarga:

template <class T, class U> T fun(U obj); // primary template 
template <class U> void Fun<void, U>(U obj); // illegal pertial 
// specialization 
template <class T> T fun (Window obj); // legal (overloading) 

Si desea profundizar en esto, se puede leer acerca de este tema en profundidad en "Modern C++ Diseño" de A. Alexandrescu.

+0

+1 para recuperar las sobrecargas de la plantilla. Esta es una herramienta que rara vez pienso usar, pero que hace el trabajo en algunas situaciones. –

0

Solución 1. mover toda la implementación a una clase base como B_Base. luego especialízate en flotar para anular el algúnFunc. como a continuación

template <typename F, typename I> 
    class B : B_Base<F, I> 
    { 
    } 

    template <typename I> 
    class B<float, I> : B_Base<flat, I> 
    { 
    public: 
     void someFunc() {....} 
    }; 

Solución 2. Uso sobrecarga de la función, flotador poner como entrada o impulsar :: is_same de su expedición.desafortunadamente, usted funciona algunaFunc no tiene parámetro. por lo que es necesario cambiar la interfaz.

Cuestiones relacionadas