Je suis allé plus loin dans mes recherches et j'ai effectivement vu que la réponse à la question 2 n'est pas dans les opérations de copie mais bien de déplacement. Ce code compile très bien :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| #include <iostream>
#include <type_traits>
class Foo {
public:
// Ctor
Foo(int& r) :
ref(r) {
}
// Copy
Foo(const Foo& other) = delete;
Foo& operator=(const Foo& other) = delete;
// Move
Foo(Foo&& other) = default;
Foo& operator=(Foo&& other) {
(void) other;
return *this;
}
private:
int& ref;
};
int main() {
static_assert(std::is_swappable<Foo>(), "Foo not swappable");
int v = 42;
int w = 66;
Foo e(v), f(w);
std::swap(e, f);
} |
Il reste donc à répondre à la question 1 
Je viens de tester de rajouter template<> et ça ne règle pas le problème. Si les opérations de déplacement sont présentes, ça fonctionne bien entendu, mais en les supprimant j'ai une erreur géniale :
g++ -std=c++17 "-IC:\\Users\\Greextpgr\\workspace\\Tests/" -O0 -g3 -pedantic -Wall -Wextra -c -fmessage-length=0 -o main.o "..\\main.cpp"
..\main.cpp:28:6: error: template-id 'swap<>' for 'void std::swap(Foo&, Foo&)' does not match any template declaration
void swap(Foo& lhs, Foo& rhs) {
^~~~
En revanche, en se plaçant dans une version qui compile et en mettant un std::cout << __PRETTY_FUNCTION__ << std::endl; dans le corps de la fonction swap(), on passe de
void std::swap(Foo&, Foo&)
à
typename std::enable_if<std::__and_<std::__not_<std::__is_tuple_like<_Tp> >, std::is_move_constructible<_Tp>, std::is_move_assignable<_Tp> >::value>::type std::swap(_Tp&, _Tp&) [with _Tp = Foo; typename std::enable_if<std::__and_<std::__not_<std::__is_tuple_like<_Tp> >, std::is_move_constructible<_Tp>, std::is_move_assignable<_Tp> >::value>::type = void]
Un tel nom ne donne envie de dire que même si un swap() custom est fourni, il faut être move assignable et move constructible. Et c'est cohérent avec le message d'erreur ci-dessus...
Partager