Why is derived class move constructible when base class isn't?
Because:
A defaulted move constructor that is defined as deleted is ignored by overload resolution.
([class.copy]/11)
Bar
's move constructor is explicitly deleted, so Bar
cannot be moved. But Foo<Bar>
's move constructor is implicitly deleted after being implicitly declared as defaulted, due to the fact that the Bar
member cannot be moved. Therefore Foo<Bar>
can be moved using its copy constructor.
Edit: I also forgot to mention the important fact that an inheriting constructor declaration such as using Base::Base
does not inherit default, copy, or move constructors, so that's why Foo<Bar>
doesn't have an explicitly deleted move constructor inherited from Bar
.
1. The behavior of std::is_move_constructible
This is expected behavior of std::is_move_constructible:
Types without a move constructor, but with a copy constructor that accepts
const T&
arguments, satisfystd::is_move_constructible
.
Which means with a copy constructor it's still possible to construct T
from rvalue reference T&&
. And Foo<Bar>
has an Implicitly-declared copy constructor.
2. The implicitly-declared move constructor of Foo<Bar>
Why does compiler generates move constructor despite base class being non-move-constructible?
In fact, the move constructor of Foo<Bar>
is defined as deleted, but note that the deleted implicitly-declared move constructor is ignored by overload resolution.
The implicitly-declared or defaulted move constructor for class
T
is defined as deleted in any of the following is true:... T has direct or virtual base class that cannot be moved (has deleted, inaccessible, or ambiguous move constructors); ...
The deleted implicitly-declared move constructor is ignored by overload resolution (otherwise it would prevent copy-initialization from rvalue).
3. The different behavior between Bar
and Foo<Bar>
Note that the move constructor of Bar
is declared as deleted
explicitly, and the move constructor of Foo<Bar>
is implicitly-declared and defined as deleted
. The point is that the deleted implicitly-declared move constructor is ignored by overload resolution, which makes it possible to move construct Foo<Bar>
with its copy constructor. But the explicitly deleted move constructor will participate in overload resolution, means when trying to move constructor Bar
the deleted move constructor will be selected, then the program is ill-formed.
That's why Foo<Bar>
is move constructible but Bar
is not.
The standard has an explicit statement about this. $12.8/11 Copying and moving class objects [class.copy]
A defaulted move constructor that is defined as deleted is ignored by overload resolution ([over.match], [over.over]). [ Note: A deleted move constructor would otherwise interfere with initialization from an rvalue which can use the copy constructor instead. — end note ]