9

Wie spezialisiere ich eine Funktionsvorlage, die einen universellen Referenzparameter verwendet?Spezialisieren einer Funktionsvorlage, die einen universellen Referenzparameter verwendet

foo.hpp:

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

foo.cpp

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

Hier Class ist nicht mehr eine davon abgeleitete Typ und somit ist Class genau; Es kann unmöglich Class & sein, so dass Regeln für kollabierende Referenzen mir hier nicht weiterhelfen. Ich könnte vielleicht eine andere Spezialisierung erstellen, die einen Class & Parameter (ich bin mir nicht sicher), aber das impliziert duplizieren aller Code enthält foo für jede mögliche Kombination von Rvalue/Lvalue Referenzen für alle Parameter, die universellen Referenzen angenommen werden soll vermeiden.

Gibt es einen Weg, dies zu erreichen?

Um genauer zu sein über mein Problem, falls es einen besserer Weg, es zu lösen ist:

Ich habe ein Programm, das zum größten Teil auf mehr Spiel-Server und jeder Server verbinden kann, ruft alles durch der selbe Name. Allerdings haben sie für einige Dinge leicht unterschiedliche Versionen. Es gibt ein paar verschiedene Kategorien, in denen diese Dinge sein können: eine Bewegung, ein Gegenstand usw. Ich habe eine generische Art von "Move String to Move Enum" -Satz von Funktionen geschrieben, um internen Code aufzurufen, und mein Server-Interface-Code ist ähnlich Funktionen. Einige Server verfügen jedoch über ihre eigene interne ID, mit der sie kommunizieren, einige verwenden Zeichenfolgen und einige verwenden beide in unterschiedlichen Situationen.

Nun, was ich tun möchte, ist dies ein wenig generischer.

Ich möchte etwas wie ServerNamespace::server_cast<Destination>(source) anrufen können. Dies würde es mir ermöglichen, von einer zu einer std::string oder ServerMoveID zu werfen. Intern muss ich möglicherweise eine Kopie erstellen (oder verschieben), da einige Server erfordern, dass ich eine Historie der gesendeten Nachrichten aufbewahre. Universelle Referenzen scheinen die offensichtliche Lösung für dieses Problem zu sein.

Die Header-Datei ich jetzt denke aussetzen würde einfach:

namespace ServerNamespace { 

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

} 

Und die Implementierungsdatei alle rechtlichen Conversions als Vorlage Spezialisierungen definieren würde.

+1

Sollte 'f'' 'foo'' sein? Was ist der Kontext des Problems? Sie wollen in der Regel Überladungen, keine Spezialisierungen. – GManNickG

+0

@GManNickG Vielleicht habe ich die falsche Terminologie verwendet.Ich habe meine Frage detaillierter bearbeitet, was ich erreichen möchte. –

+0

Für eine wirklich nette Zusammenfassung zu diesem Thema, siehe: https://mortoray.com/2013/06/03/overriding-the-broken-universal-reference -t/ –

Antwort

2

Die beste Lösung ist meiner Meinung nach einem Tag Versandsystem verwenden, in dem Sie auf Tags überlasten und nicht die tatsächliche Art:

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

Ich muss darüber noch etwas nachdenken. –

1

Die erweiterbar was zu tun ist eine Template-Klasse Spezialisierung zu erstellen.

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

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

Der Grund, warum ich sagen, dass dies die dehnbar ist, weil man überall eine Spezialisierung hinzufügen können, innerhalb oder außerhalb der Datei, die auch immer definiert.

Dies ist nicht exklusiv für die von Pubby vorgeschlagene Tagversandlösung.