2009-04-20 10 views
8

Estoy tratando de implementar una función de plantilla con identificadores anulados de manera diferente mediante la especialización de plantillas.especialización de plantillas para funciones de miembros estáticos; ¿cómo?

El siguiente código me da una "especialización explícita en el ámbito no-espacio de nombres" en gcc:

template <typename T> 
static T safeGuiCall(boost::function<T()> _f) 
{ 
    if (_f.empty()) 
     throw GuiException("Function pointer empty"); 
    { 
     ThreadGuard g; 
     T ret = _f(); 
     return ret; 
    } 
} 

// template specialization for functions wit no return value 
template <> 
static void safeGuiCall<void>(boost::function<void()> _f) 
{ 
    if (_f.empty()) 
     throw GuiException("Function pointer empty"); 
    { 
     ThreadGuard g; 
     _f(); 
    } 
} 

He intentado moverlo fuera de la clase (la clase no se templated) y en el espacio de nombres, pero luego aparece el error "La especialización explícita no puede tener una clase de almacenamiento". He leído muchas discusiones sobre esto, pero las personas no parecen estar de acuerdo en cómo especializar las plantillas de funciones. ¿Algunas ideas?

Respuesta

12

Cuando usted se especializa un método de plantilla, debe hacerlo fuera de los soportes de clase:

template <typename X> struct Test {}; // to simulate type dependency 

struct X // class declaration: only generic 
{ 
    template <typename T> 
    static void f(Test<T>); 
}; 

// template definition: 
template <typename T> 
void X::f(Test<T>) { 
    std::cout << "generic" << std::endl; 
} 
template <> 
inline void X::f<void>(Test<void>) { 
    std::cout << "specific" << std::endl; 
} 

int main() 
{ 
    Test<int> ti; 
    Test<void> tv; 
    X::f(ti); // prints 'generic' 
    X::f(tv); // prints 'specific' 
} 

Cuando se toma fuera de la clase, debe quitar el palabra clave 'estática' La palabra clave estática fuera de la clase tiene un significado específico diferente de lo que probablemente desee.

template <typename X> struct Test {}; // to simulate type dependency 

template <typename T> 
void f(Test<T>) { 
    std::cout << "generic" << std::endl; 
} 
template <> 
void f<void>(Test<void>) { 
    std::cout << "specific" << std::endl; 
} 

int main() 
{ 
    Test<int> ti; 
    Test<void> tv; 
    f(ti); // prints 'generic' 
    f(tv); // prints 'specific' 
} 
+0

hm He intentado lo mismo ahora, pero lo puse en un archivo .hpp y traté de incluirlo ... luego recibí el error "definición múltiple de vodi X: ff (Prueba ). No puedo ver qué haría ser la diferencia? – Rolle

+1

¿Fue un compilador o un error de enlazador?Si se trata de un error del compilador, significa que probablemente esté incluyendo el encabezado de la plantilla más de una vez y faltan los resguardos del encabezado, y por lo tanto la doble definición: el compilador está viendo dos definiciones (lamentablemente exactas) para la implementación. –

+0

¿Por qué debo agregar en línea para el primer caso? Si no, recibo un error de compilación. – sop

3

Se puede declarar la especialización explícita de la misma manera en que se define una función miembro fuera de su clase:

class A 
{ 
public: 
    template <typename T> 
    static void foo() {} 
}; 

template <> 
void A::foo<void>() 
{ 
} 
+0

Gracias por la respuesta. Para mí no importa si están dentro de una clase o no; pero no puedo hacer que funcione de cualquier manera. ¿Está mi sintaxis incorrecta o algo en el código que proporcioné? – Rolle

+0

El punto es que explícitamente se especializa la función en el espacio de nombres con un declarador de funciones calificado. C++ no le permite volver a agregar la palabra clave "estática" para que simplemente la elimine. Mi ejemplo anterior muestra cómo especializar explícitamente un miembro estático. –

2

Su problema parece estar con la función impulso :: - las siguientes especialidades trabajan:

+0

lo he intentado pero no funciona. ¿Compiló bajo gcc? Creo que funciona bajo VS por ejemplo ... – Rolle

+0

Esta es la versión de G ++ 3.4.5 –

+0

Es esta estática - eliminarlos y todos deberían ser weel, compila con comeau, actualizaré la respuesta –

4

no aparece de una respuesta a su pregunta, pero se puede escribir este

template <typename T> 
static T safeGuiCall(boost::function<T()> _f) 
{ 
     if (_f.empty()) 
       throw GuiException("Function pointer empty"); 
     { 
       ThreadGuard g; 
       return _f(); 
     } 
} 

Debería funcionar incluso si _f() devuelve 'nulo'

Editar: En un caso más general, creo que deberíamos preferir la sobrecarga de funciones en lugar de la especialización. Aquí hay una buena explicación para esto: http://www.gotw.ca/publications/mill17.htm

+1

sí, muy buen punto –

+0

I estoy bastante seguro de que no funcionará. T no está definido en ninguna parte? – Rolle

+0

@Rolle Lo sentimos "plantilla " no sobrevivió para copiar/pegar. – Rexxar

1

Tuve un problema similar. Si miras la publicación original, dejé la primera estática, pero saqué la segunda y AMBOS errores desaparecieron.

Cuestiones relacionadas