You don't need vector, a simpler example would be just:
C1 a; C1 b(std::move(a)); // error: C1's copy constructor is deleted From [class.copy]:
If the definition of a class
Xdoes not explicitly declare a move constructor, a non-explicit one will be implicitly declared as defaulted if and only if
(9.1) —Xdoes not have a user-declared copy constructor,
(9.2) —Xdoes not have a user-declared copy assignment operator,
(9.3) —Xdoes not have a user-declared move assignment operator, and
(9.4) —Xdoes not have a user-declared destructor.
C1 has a user-declared destructor, therefore it does not have a move constructor. C1 does however have an implicitly declared copy constructor
If the class definition does not explicitly declare a copy constructor, a non-explicit one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted; otherwise, it is defined as defaulted (8.4). The latter case is deprecated if the class has a user-declared copy assignment operator or a user-declared destructor.
The full set of constructors on C1, explicit and implicit, looks like:
C1(); C1(C1 const& ) = delete;default; // becausebut ofalso noncopyabledelete ~C1(); So trying to construct a C1 from an rvalue of type C1 will match that implicitly declared copy constructor as the best match (nothing else is viable), but that constructor is deleted because noncopyable's copy constructor is deleted, so the entire expression is ill-formed.
That's why the error message mentions the constructor. That move-construction is ill-formed because the best match for that move-construction is the copy constructor is ill-formed. It can't mention the move constructor because there is no move constructor, and the destructor isn't relevant to the expression at hand. When you changed the base class to be copyable, now C1 also becomes copyable - so no error. There's still no move constructor, it's just that now there's a viable candidate for move construction.