- est la bonne utilisation de
swap
. Écrivez-le de cette façon lorsque vous écrivez du code «bibliothèque» et que vous souhaitez activer ADL (recherche dépendante des arguments) swap
. De plus, cela n'a rien à voir avec SFINAE.
template<class T>
void foo(T& lhs, T& rhs) {
using std::swap;
swap(lhs, rhs);
}
- Est la bonne façon de fournir une
swap
fonction à votre classe.
namespace Foo {
class Bar{};
void swap(Bar& lhs, Bar& rhs) {
}
}
Si swap
est maintenant utilisé comme indiqué en 1), votre fonction sera trouvée. De plus, vous pouvez faire de cette fonction un ami si vous en avez absolument besoin, ou fournir un membre swap
appelé par la fonction gratuite:
class Bar{
public:
friend void swap(Bar& lhs, Bar& rhs) {
}
};
class Bar{
public:
void swap(Bar& other) {
}
};
void swap(Bar& lhs, Bar& rhs) {
lhs.swap(rhs);
}
...
- Vous voulez dire une spécialisation explicite. Le partiel est encore quelque chose d'autre et également impossible pour les fonctions, uniquement les structures / classes. En tant que tel, puisque vous ne pouvez pas vous spécialiser
std::swap
pour les classes de modèles, vous devez fournir une fonction gratuite dans votre espace de noms. Pas mal, si je puis dire. Désormais, une spécialisation explicite est également possible, mais généralement vous ne souhaitez pas spécialiser un modèle de fonction :
namespace std
{
template<>
void swap<Bar>(Bar& lhs, Bar& rhs) noexcept {
}
}
- Non, car 1) est distinct de 2) et 3). De plus, avoir à la fois 2) et 3) conduira à toujours avoir 2) choisi, car il convient mieux.
using std::swap;
n'active pas ADL, il permet simplement au compilateur de localiserstd::swap
si ADL ne trouve pas une surcharge appropriée.Pour répondre à l'EDIT, où les classes peuvent être des classes modèles, vous n'avez pas du tout besoin de spécialisation. considérez une classe comme celle-ci:
template <class T> struct vec3 { T x,y,z; };
vous pouvez définir des classes telles que:
vec3<float> a; vec3<double> b; vec3<int> c;
si vous voulez être en mesure de créer une fonction pour implémenter les 3 swaps (pas que cet exemple de classe le justifie), vous faites comme Xeo dit dans (2) ... sans spécialisation mais créez simplement une fonction de modèle régulière:
template <class T> void swap(vec3<T> &a, vec3<T> &b) { using std::swap; swap(a.x,b.x); swap(a.y,b.y); swap(a.z,b.z); }
La fonction de modèle d'échange doit être située dans le même espace de noms que la classe que vous essayez d'échanger. la méthode suivante trouvera et utilisera ce swap même si vous ne référencez pas cet espace de noms à l'aide d'ADL:
using std::swap; swap(a,b);
la source
Il semble que (2) ( autonome
swap
dans le même espace de noms où la classe définie par l'utilisateur est déclarée ) soit le seul moyen autorisé de fournirswap
une classe définie par l'utilisateur, car l'ajout de déclarations à l'espace de nomsstd
est généralement un comportement non défini. Extension de l'espace de noms std (cppreference.com) :Et
swap
ne fait pas partie de ces exceptions. Donc, ajouter votre propreswap
surcharge à l'std
espace de noms est un comportement indéfini.Il est également dit que la bibliothèque standard utilise un appel non qualifié à la
swap
fonction afin d'appeler définiswap
par l'utilisateur pour une classe d'utilisateurs si une telle définition utilisateurswap
est fournie.Remplaçable (cppreference.com) :
swap (www.cplusplus.com) :
Mais notez que l'utilisation directe de la
std::swap
fonction pour une classe définie par l'utilisateur appelle la version générique destd::swap
au lieu de celle définie par l'utilisateurswap
:my::object a, b; std::swap(a, b); // calls std::swap, not my::swap
Il est donc recommandé d'appeler la
swap
fonction en code utilisateur de la même manière que dans la bibliothèque standard:my::object a, b; using std::swap; swap(a, b); // calls my::swap if it is defined, or std::swap if it is not.
la source