2011-01-02 5 views
4

Je voudrais surcharger std :: swap dans ma classe de template. Dans le code suivant (simplifié)C++, surcharge de std :: swap, erreur du compilateur, 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 

il y a une erreur de compilation (uniquement dans VS 2010):

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

Je ne sais pas pourquoi, std :: swap doit être overoaded ... Utilisation Le code g ++ fonctionne parfaitement. Sans modèles (c'est-à-dire Point2D n'est pas une classe de modèle) ce code fonctionne également ..

Merci pour votre aide.

+2

Vous n'êtes pas censé ** surcharger ** 'std :: swap', vous êtes censé ** le spécialiser **. Les réponses à la question liée à villintehaspam expliquent cette distinction en donnant des exemples. Mais ** spécialisation partielle ** n'est pas possible pour les modèles de fonction, vous devrez donc définir votre implémentation dans votre propre espace de nom et faire appel à la recherche Koenig. –

+0

Note: la norme dit "Une déclaration de spécialisation explicite ne doit pas être une déclaration d'ami." C'était une bonne idée cependant. –

Répondre

5

Veuillez consulter How to overload std::swap(). Fondamentalement, vous êtes autorisé à faire une spécialisation de std :: swap, mais pas de surcharge.

Donc, il est possible de créer une version spécifique pour un type spécifique Point<> (par exemple Point<float>), mais pas pour Point<T>.

+1

Non mais ... vous pouvez mettre une surcharge de swap dans l'espace de noms où 'Point ' est défini, et il sera trouvé via Koenig lookup (alias argument-dependent lookup). –

+0

@Ben Voigt: Vrai pour les cas simples comme lorsque vous appelez swap (a, b) dans votre propre code - cependant, il y a beaucoup de code qui appelle std :: swap explicitement (je pense que c'est le cas dans certaines implémentations de la bibliothèque standard) et cela n'aidera pas alors. – villintehaspam

+0

@villintehaspam Il est un peu inconfortable de spécialiser swap pour plus de types de données (double, floast, ...): swap en ligne (Point2D & p1, Point2D & p2) {p1.swap (p2); } – Ian

2

Je sais que vous ne l'avez pas demandé, mais puisque vous utilisez VC10, avec un constructeur de déplacement et un opérateur d'affectation de déplacement devrait faire std::swap() effectuer optimal pour votre type.

+0

C'est une autre solution, j'y pensais ... – Ian

0

La raison pour laquelle il est ambigu est parce que vous avez fourni :: swap et std :: swap, alors vous using 'd std :: swap. Vous avez maintenant swap et std :: swap dans l'espace de noms global. Le compilateur ne sait donc pas si vous voulez dire: swap ou std :: swap. Cependant, en fournissant un opérateur/constructeur de déplacement, le swap fonctionnera de façon optimale, de manière réaliste.

Questions connexes