So there are several misconceptions going on here. Richard noted earlier today that this really doesn't have anything to do with reference_wrapper:
#include <functional>
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <cxxabi.h>
template <typename T>
std::unique_ptr<char, void(*)(void*)>
type_name(const T&)
{
return std::unique_ptr<char, void(*)(void*)>
(
__cxxabiv1::__cxa_demangle(typeid(T).name(), nullptr,
nullptr, nullptr),
std::free
);
}
struct MyType {virtual void foo() = 0;};
struct X : MyType {virtual void foo() {}};
int main()
{
X a, b;
MyType& one = a;
MyType& two = b;
auto mypair = std::make_pair(std::ref(one), std::ref(two));
std::cout << type_name(mypair).get() << '\n';
}
std::__1::pair<MyType&, MyType&>
I.e. make_pair converts reference_wrapper<T> into T&.
So the question now becomes: Can you use the generic std::swap on two lvalues of MyType. It is easy to see if you try out a simplified home-made swap:
#include <functional>
#include <algorithm>
#include <cstdlib>
#include <iostream>
template <class T>
void
my_swap(T& x, T& y)
{
T tmp(std::move(x));
x = std::move(y);
y = std::move(tmp);
}
struct MyType {virtual void foo() = 0;};
struct X : MyType {virtual void foo() {}};
int main()
{
X a, b;
MyType& one = a;
MyType& two = b;
auto mypair = std::make_pair(std::ref(one), std::ref(two));
my_swap(mypair.first, mypair.second);
}
test.cpp:64:7: error: variable type 'MyType' is an abstract class
T tmp(std::move(x));
^
test.cpp:82:5: note: in instantiation of function template specialization 'my_swap<MyType>' requested here
my_swap(mypair.first, mypair.second);
^
1 error generated.
Or perhaps more concisely:
static_assert(std::is_move_constructible<MyType>::value, "MyType is not move constructible");
Fires:
test.cpp:79:5: error: static_assert failed "MyType is not move constructible"
static_assert(std::is_move_constructible<MyType>::value, "MyType is not move constructible");
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 error generated.
Otoh, std::reference_wrapper<MyType> is both MoveConstructible and MoveAssignable. And that's why when you assign the pair<MyType&, MyType&> returned from make_pair back into a std::pair<std::reference_wrapper<MyType>,std::reference_wrapper< MyType >>, it works.
Howard