2011-01-02 6 views
4

Ich möchte std :: swap in meiner Template-Klasse überladen. Im folgenden Code (vereinfacht)C++, Überladen std :: swap, Compiler Fehler, VS 2010

#ifndef Point2D_H 
#define Point2D_H 

template <class T> 
class Point2D 
{ 
    protected: 

      T x; 
      T y; 

    public: 
      Point2D() : x (0), y (0) {} 
      Point2D(const T &x_, const T &y_) : x (x_), y (y_) {} 
      .... 

    public: 

      void swap (Point2D <T> &p); 
}; 


template <class T> 
inline void swap (Point2D <T> &p1, Point2D <T> &p2) { p1.swap (p2); } 


namespace std 
{ 
    template <class T> 
    inline void swap (Point2D <T> &p1, Point2D <T> &p2) { p1.swap (p2); } 
} 

template <class T> 
void Point2D <T>::swap (Point2D <T> &p) 
{ 
    using (std::swap); 
    swap (x, p.x); 
    swap (y, p.y); 
} 

#endif 

gibt es einen Compiler-Fehler (nur in VS 2010):

error C2668: 'std::swap' : ambiguous call to overloaded 

Ich weiß nicht, warum, std :: Swap overoaded werden soll ... Mit g ++ Code funktioniert perfekt. Ohne Vorlagen (d. H. Point2D ist keine Vorlagenklasse) funktioniert dieser Code auch.

Vielen Dank für Ihre Hilfe.

+2

Sie sollen nicht ** std :: swapping ** überladen, Sie sollen ** es spezialisieren **. Antworten auf die von villintehaspam verbundene Frage erklären diese Unterscheidung zusammen mit dem Geben von Beispielen. Aber ** partielle Spezialisierung ** ist für Funktionsschablonen nicht möglich, daher müssen Sie Ihre Implementierung in Ihrem eigenen Namensraum definieren und sich auf Koenig-Lookup verlassen. –

+0

Hinweis: Der Standard besagt "Eine explizite Spezialisierungserklärung darf keine Freundschaftsdeklaration sein". Es war eine nette Idee. –

Antwort

5

Bitte siehe How to overload std::swap(). Grundsätzlich dürfen Sie eine Spezialisierung von std :: swap, aber keine Überladung vornehmen.

So ist es in Ordnung, eine spezifische Version für einen spezifischen Point<> Typ zu erstellen (sagen Sie Point<float>), aber nicht für irgendeinen Point<T>.

+1

Nein, aber ... Sie können eine Überladung von swap in den Namespace setzen, in dem 'Point ' definiert ist, und es wird über Koenig lookup (aka-abhängige Suche) gefunden. –

+0

@Ben Voigt: Wahr für einfache Fälle wie wenn Sie swap (a, b) in Ihrem eigenen Code aufrufen - allerdings gibt es viel Code, der std :: swap explizit aufruft (ich denke, das ist zumindest in einigen Implementierungen von die Standardbibliothek) und das wird dann nicht helfen. – villintehaspam

+0

@villintehaspam Es ist ein wenig unangenehm, Swap für mehr Datentypen (double, floast, ...) zu spezialisieren: inline void swap (Point2D & p1, Point2D & p2) {p1.swap (p2); } – Ian

2

Ich weiß, dass Sie dies nicht gefragt, aber da Sie VC10 verwenden, einen Operator bewegen Konstruktor und eine bewegen Zuordnung Bereitstellung sollte std::swap() ausführen optimal für Ihre Art machen.

+0

Es ist eine andere Lösung, ich habe darüber nachgedacht ... – Ian

0

Der Grund, warum es mehrdeutig ist, ist, weil Sie :: swap und std :: swap zur Verfügung gestellt haben, dann Sie using 'd std :: swap. Jetzt haben Sie sowohl :: swap und std :: swap im globalen Namespace. Der Compiler weiß also nicht, ob Sie :: swap oder std :: swap meinen.

Die Bereitstellung von move operator/constructor wird den Tausch jedoch optimal und realistisch gestalten.