- é o uso adequado de
swap
. Escreva desta forma quando você escreve o código de "biblioteca" e deseja habilitar ADL (pesquisa dependente de argumento) swap
. Além disso, isso não tem nada a ver com SFINAE.
template<class T>
void foo(T& lhs, T& rhs) {
using std::swap;
swap(lhs, rhs);
}
- É a maneira correta de fornecer uma
swap
função para sua classe.
namespace Foo {
class Bar{};
void swap(Bar& lhs, Bar& rhs) {
}
}
Se swap
agora for usado como mostrado em 1), sua função será encontrada. Além disso, você pode tornar essa função um amigo se for absolutamente necessário, ou fornecer um membro swap
que é chamado pela função gratuita:
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);
}
...
- Você quer dizer uma especialização explícita. Parcial ainda é outra coisa e também não é possível para funções, apenas structs / classes. Como tal, desde que você não pode se especializar
std::swap
para classes de modelo, você tem de fornecer uma função gratuita no seu namespace. Não é uma coisa ruim, se assim posso dizer. Agora, uma especialização explícita também é possível, mas geralmente você não deseja especializar um modelo de função :
namespace std
{
template<>
void swap<Bar>(Bar& lhs, Bar& rhs) noexcept {
}
}
- Não, visto que 1) é diferente de 2) e 3). Além disso, ter 2) e 3) levará a sempre 2) escolhido, porque se ajusta melhor.
using std::swap;
não ativa o ADL, apenas permite que o compilador localizestd::swap
se o ADL não encontrou uma sobrecarga adequada.Para responder ao EDIT, onde as classes podem ser classes de modelo, você não precisa de especialização. considere uma aula como esta:
template <class T> struct vec3 { T x,y,z; };
você pode definir classes como:
vec3<float> a; vec3<double> b; vec3<int> c;
se você quiser ser capaz de criar uma função para implementar todas as 3 trocas (não que esta classe de exemplo justifique), você faz exatamente como Xeo disse em (2) ... sem especialização, mas apenas faça uma função de modelo regular:
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); }
A função de modelo de troca deve estar localizada no mesmo namespace da classe que você está tentando trocar. o método a seguir encontrará e usará essa troca, mesmo que você não esteja fazendo referência a esse namespace usando ADL:
using std::swap; swap(a,b);
fonte
Parece que (2) ( independente
swap
no mesmo namespace onde a classe definida pelo usuário é declarada ) é a única maneira permitida de fornecerswap
uma classe definida pelo usuário, porque adicionar declarações ao namespacestd
é geralmente um comportamento indefinido. Estendendo o namespace std (cppreference.com) :E
swap
não é denotado como uma dessas exceções. Portanto, adicionar sua própriaswap
sobrecarga aostd
namespace é um comportamento indefinido.Também é dito que a biblioteca padrão usa uma chamada não qualificada para a
swap
função a fim de chamar definidoswap
pelo usuário para uma classe de usuário, se tal definido pelo usuárioswap
for fornecido.Swappable (cppreference.com) :
swap (www.cplusplus.com) :
Mas observe que usar diretamente a
std::swap
função para uma classe definida pelo usuário chama a versão genérica de emstd::swap
vez da definida pelo usuárioswap
:my::object a, b; std::swap(a, b); // calls std::swap, not my::swap
Portanto, é recomendável chamar a
swap
função no código do usuário da mesma forma que é feito na biblioteca padrão:my::object a, b; using std::swap; swap(a, b); // calls my::swap if it is defined, or std::swap if it is not.
fonte