swap, abs & Co im template mit oder ohne std::
-
Simon2 schrieb:
Alternativ kannst Du natürlich einen zusätzlichen template-Parameter einführen und Dir einen swap-Funktor übergeben lassen (im Extremfall ein ganzes traits-Konstrukt)
Die Verwendung einer Traits-Klasse ist zumindest für weniger allgemeine Typen/Algorithmen eine gute Idee. Allerdings würde ich die nicht als Parameter übergeben. Vielmehr würde ich die Traits-Klasse im Namespace der Template-Library definieren, mindestens eine allgemeine Implementation bereitstellen und dann den Nutzer der Lib auffordern, selbige für etwaige Sonderfälle zu spezialisieren.
-
Eine Traits-Klasse einzuführen, die dann innerhalb des Templates gerufen wird, kam mir auch schon in den Sinn. Also etwa sowas
// Code im template ... spezial_swap( x1, x2, swap_trait< T >::istEingebauterTyp() ); // -- mit struct Ja {}; struct Nein {}; template< typename T > struct swap_traits { typedef Nein istEingebauterTyp; }; template<> struct< int > swap_traits // und für char, short, double usw. { typedef Ja istEingebauterTyp; }; // -- und template< typename T > void spezial_swap( T& a, T& b, Ja ) { std::swap( a, b ); }
aber zurück zur ursprünglichen Frage. Wo ist bei dieser Konstruktion der Vorteil gegenüber dem einfachen
{ using namespace std; // damit swap( int, int ) auch funkt swap( first, second ); }
meinetwegen auch mit
using std::swap
.Gruß
Werner
-
@Werner Salomon
Was die Traitsklasse angeht, so würde ich die einfachste Variante vorschlagen:namespace YourLib { template <class T> struct Swap { static void swap(T& t, T& u) { std::swap(t, u); } }; template <class T> void func(T& o, T& k) { YourLib::Swap<T>::swap(o, k); ... } }
Client-Code kann dann einfach YourLib::Swap spezialisieren.
-
HumeSikkins schrieb:
Man darf std::swap im Namespace std spezialisieren. Man darf aber leider kein neues swap zu std hinzufügen. D.h. für normale Typen, also nicht Templates, sollte man wie folgt vorgehen:
a) eigenes swap im Namespace des Typen definieren
b) std::swap im Namespace std für den Typen spezialisieren.Hallo Hume,
Oops, ich hatte diese Deine Antwort zu spät gesehen. Ich stehe jetzt etwas auf dem Schlauch. Was heißt 'darf spezialisieren, aber nicht hinzufügen'? Beispiel
class MDK // MeineDickeKlasse { // viel Zeug friend void swap( MDK& a, MDK& b ); };
Was ist jetzt
namespace std { swap( MDK& a, MDK& b ) { ::swap( a, b ); } }
ist das spezialisieren oder hinzufügen? Und wie geht dann das jeweils andere?
Gruß
Werner
-
HumeSikkins schrieb:
Client-Code kann dann einfach YourLib::Swap spezialisieren.
Hallo Hume,
Was der Client aber vielleicht doof findet, da er nicht nur 'YourLib' sondern auch 'MyLib' und 'Lib3' verwendet, wo eine ähnliche Problematik auftaucht. Ein Client wird doch (wenn überhaupt) ein
swap( ClientKlasse& a, ClientKlasse& b )
zur Verfügung stellen, was in jedem Fall über namespace lookup gefunden werden sollte.
Gruß
Werner
-
Hallo,
std::swap ist eine Templatefunktion, d.h. irgendwo in namspace std steht:namspace std { template <class T> void swap(T& t, T& u); }
Einige Standard-Header definieren auch noch Überladungen für swap. Z.B. <vector>
namspace std { // Überladung - nicht Spezialisierung! template <class T> void swap(std::vector<T>& t, std::vector<T>& u); }
Du als "normaler" C++ Benutzer, darfst std::swap in std spezialisieren, aber nicht überladen. D.h.
class MDK // MeineDickeKlasse { // viel Zeug friend void swap( MDK& a, MDK& b ); }; namespace std { // OK - Spezialisierung template <> void swap(MDK& lhs, MDK& rhs); }
aber nicht:
template <class T> class MDK // MeineDickeKlasse { // viel Zeug friend void swap( MDK& a, MDK& b ); }; namespace std { // NICHT ERLAUBT - Überladung! template <class T> void swap(MDK<T>& lhs, MDK<T>& rhs); }
-
Werner Salomon schrieb:
Was der Client aber vielleicht doof findet, da er nicht nur 'YourLib' sondern auch 'MyLib' und 'Lib3' verwendet, wo eine ähnliche Problematik auftaucht.
Exakt. Deshalb habe ich die Traitsklasse ja auch nur für "weniger allgemeine Typen/Algorithmen" vorgeschlagen. Für sowas wie swap landest du sonst direkt bei der "tausend-kleine-Adapter"-Problematik.
Leztlich liegt der Fehler beim Standard. Hätte man dort einfach eine Klasse für swap verwendet, gäbe es kein Problem, da man diese dann beliebig spezialisieren könnte und Template-Code so immer std::swap schreiben könnte.
-
HumeSikkins schrieb:
Du als "normaler" C++ Benutzer, darfst std::swap in std spezialisieren, aber nicht überladen.
Danke für Deine ausführlichen Erläuterung. Also der Unterschied ist nur template oder nicht template, oder! Kannst Du mir jetzt noch sagen, wo das im Standard steht.
Gruß
Werner
-
Werner Salomon schrieb:
Kannst Du mir jetzt noch sagen, wo das im Standard steht.
17.4.3.1/1:
It is undefined for a C++ program to add declarations or definitions to namespace std or namespaces within namespace std unless otherwise specified. A program may add template specializations for any standard library template to namespace std. Such a specialization (complete or partial) of a standard library template results in undefined behavior unless the declaration depends on a user-defined name of external linkage and unless the specialization meets the standard library requirements for the original template.
Da std::swap ein Funktionstemplate ist und da Funktionstemplate nur vollständig, nicht aber partiell spezialisiert werden können, ergibt sich für swap das von mir gesagte.
-
@Hume: Danke