2009-04-20 3 views
8

Sto tentando di implementare una funzione di modello con le maniglie vuote in modo diverso utilizzando la specializzazione del modello.per funzioni membro statiche; come?

Il seguente codice mi dà una "specializzazione esplicita in ambito non-spazio dei nomi" in 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(); 
    } 
} 

ho provato a spostare fuori della classe (la classe non è templato) e nello spazio dei nomi, ma quindi viene visualizzato l'errore "La specializzazione esplicita non può avere una classe di archiviazione". Ho letto molte discussioni a riguardo, ma le persone non sembrano concordare su come specializzare i modelli di funzione. Qualche idea?

risposta

12

Quando si specializzano un metodo basato su modelli, è necessario farlo al di fuori delle fasce di classe:

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' 
} 

Quando si prende fuori della classe, è necessario rimuovere le parola chiave 'statica'. La parola chiave statica al di fuori della classe ha un significato specifico diverso da quello che probabilmente desideri.

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 Ho provato la stessa cosa adesso, ma l'ho messo in un file .hpp e ho provato ad includerlo ... poi ho ricevuto l'errore "definizione multipla di vodi X: ff (Test ). Non riesco a vedere cosa sarebbe – Rolle

+1

È stato un errore del compilatore o del linker?Se si tratta di un errore del compilatore, significa che probabilmente si include l'intestazione del modello più di una volta e mancano le protezioni dell'intestazione, e quindi la doppia definizione: il compilatore sta visualizzando due (ahimè esattamente esatte) definizioni per l'implementazione. –

+0

Perché devo aggiungere in linea per il primo caso? In caso contrario, sto ricevendo un errore di compilazione. – sop

3

È possibile dichiarare la specializzazione esplicita nello stesso modo che ci si definisce una funzione di membro al di fuori della sua classe:

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

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

Grazie per la risposta. Per me non importa se sono all'interno di una classe o no; ma non posso farlo funzionare in entrambi i modi. La mia sintassi è errata o qualcosa del codice che ho fornito? – Rolle

+0

Il punto è che si specializzi esplicitamente la funzione nel namespace con un dichiaratore di funzioni qualificato. C++ non ti consente di aggiungere nuovamente la parola chiave 'statica' in modo da rimuoverla. Il mio esempio sopra mostra come specializzare esplicitamente un membro statico. –

2

Il tuo problema sembra essere con la funzione boost :: - le seguenti specializzazioni funzionano:

+0

mi dispiace provato ma non funziona. Hai compilato sotto gcc? Penso che funzioni sotto VS per esempio ... – Rolle

+0

Questa è la versione g ++ 3.4.5 –

+0

È questa statica - rimuoverli e tutto dovrebbe essere weel, compila con comeau, aggiornerò la risposta –

4

non è direttamente una risposta alla tua domanda, ma si può scrivere questo

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

Dovrebbe funzionare anche se _f() restituisce 'void'

Modifica: In un caso più generale, penso che dovremmo preferire l'overloading delle funzioni anziché la specializzazione. Ecco una buona spiegazione per questo: http://www.gotw.ca/publications/mill17.htm

+1

sì ottimo punto –

+0

I Sono abbastanza sicuro che non funzionerà. T non è definito da nessuna parte? – Rolle

+0

@Rolle Spiacente "modello " non è sopravvissuto per copiare/incollare. – Rexxar

1

Ho avuto un problema simile. Se guardi il post originale, ho lasciato la prima statica, ma ho eliminato il secondo e ENTRAMBI gli errori sono andati via.