Per [class.copy.ctor]/8
If the definition of a class X does not explicitly declare a move constructor, a non-explicit one will be implicitly declared as defaulted if and only if [...]
- X does not have a user-declared destructor.
Since
virtual ~foo() = default;
is a user-declared destructor you no longer have a move constructor so it tries to use the copy constructor but can't because that is deleted as you have a non-copyable member.
To get the move constructor back, and to keep the default constructable, you need to add
foo() = default;
foo(foo&&) = default;
foo &operator=(foo &&) = default; // add this if you want to move assign as well
to foo
The reason you have to add foo() = default;
when you add foo(foo&&) = default;
is that foo(foo&&) = default;
is a used-declared constructor and if you have any user-declared constructors then the default constructor is no longer provided.
This is a "hack" but what you could do is move the virtual destructor into another class and then inherit from that. That will give you a virtual destructor in foo
without having to declare it and give you the default constructors you want. That would look like
struct make_virtual
{
virtual ~make_virtual() = default;
};
struct foo : make_virtual {
std::unique_ptr<int> mem;
};