9

Come si specializza un modello di funzione che utilizza un parametro di riferimento universale?Specializzazione di un modello di funzione che utilizza un parametro di riferimento universale

foo.hpp:

template<typename T> 
void foo(T && t) // universal reference parameter 

foo.cpp

template<> 
void foo<Class>(Class && class) { 
    // do something complicated 
} 

Qui, Class non è più un tipo dedotta e quindi è Class esattamente; non è possibile che sia Class &, quindi le regole di compressione di riferimento non mi saranno d'aiuto. Potrei forse creare un'altra specializzazione che prende un parametro Class & (non ne sono sicuro), ma ciò implica la duplicazione di tutto il codice contenuto all'interno di foo per ogni possibile combinazione di riferimenti rvalue/lvalue per tutti i parametri, che è quello che si suppone di riferimenti universali evitare.

C'è qualche modo per realizzare questo?

Per essere più preciso circa il mio problema nel caso in cui ci sia un modo migliore per risolverlo:

Ho un programma in grado di connettersi a più server di gioco, e ogni server, per la maggior parte, le chiamate tutto da lo stesso nome Tuttavia, hanno versioni leggermente diverse per alcune cose. Ci sono alcune categorie diverse che possono essere queste cose: una mossa, un oggetto, ecc. Ho scritto un tipo generico di "move string to move enum" insieme di funzioni per il codice interno da chiamare, e il mio codice di interfaccia del server ha simili funzioni. Tuttavia, alcuni server hanno il proprio ID interno con cui comunicano, alcuni usano stringhe e altri usano entrambi in situazioni diverse.

Ora quello che voglio fare è renderlo un po 'più generico.

Desidero poter chiamare qualcosa come ServerNamespace::server_cast<Destination>(source). Ciò mi consentirebbe di trasmettere da Move a std::string o ServerMoveID. Internamente, potrei aver bisogno di fare una copia (o spostarmi da) perché alcuni server richiedono che tenga una cronologia dei messaggi inviati. I riferimenti universali sembrano essere la soluzione ovvia a questo problema.

Il file di intestazione sto pensando in questo momento esporrebbe semplicemente questo:

namespace ServerNamespace { 

template<typename Destination, typename Source> 
Destination server_cast(Source && source); 

} 

E il file di implementazione definirebbe tutte le conversioni di legge come specializzazioni modello.

+1

Dovrebbe 'f' essere' pippo'? Inoltre, qual è il contesto del problema? Generalmente vuoi sovraccarichi, non specializzazioni. – GManNickG

+0

@GManNickG Forse ho usato la terminologia sbagliata.Ho modificato la mia domanda con maggiori dettagli su quello che sto cercando di realizzare –

+0

Per una bella recensione su questo problema, consultare: https://mortoray.com/2013/06/03/overriding-the-broken-universal-reference -t/ –

risposta

2

La soluzione migliore a mio parere è quello di utilizzare un sistema di tag spedizione in cui si esegue l'overload sui tag piuttosto che il tipo effettivo:

struct foo { 
    struct tag {}; 
}; 

struct bar { 
    struct tag {}; 
}; 

template<typename Destination, typename Source> 
Destination server_cast(Source && source, foo::tag) { 
    // foo 
} 

template<typename Destination, typename Source> 
Destination server_cast(Source && source, bar::tag) { 
    // bar 
} 

template<typename Destination, typename Source> 
Destination server_cast(Source && source) { 
    return server_cast<Destination>(std::forward<Source>(source), typename std::remove_reference<Source>::type::tag()); 
} 
+0

Dovrò pensarci un po 'di più. –

1

La cosa più estensibile per fare è di creare una specializzazione classe template.

template< class X > struct Whatever { 
    void f(){ ... } 
}; 

template<> struct Whatever<UserType> { 
    void f(){ ... } 
}; 

Il motivo dico che questo è il più estensibile è perché è possibile aggiungere una specializzazione ovunque, all'interno o all'esterno del file che definisce Qualunque cosa.

Questo è gratuito, non esclusivo, alla soluzione di invio di tag suggerita da Pubby.

Problemi correlati