1. std::is_move_constructible
的行为
这是std::is_move_constructible的预期行为:
没有移动构造函数,但具有接受const T&
参数的复制构造函数的类型符合std::is_move_constructible
。
这意味着即使有一个复制构造函数,仍然可以使用rvalue引用T&&
构造T
。而且Foo<Bar>
具有隐式声明的复制构造函数。
2. Foo<Bar>
的隐式声明移动构造函数
为什么编译器生成移动构造函数,尽管基类不可移动构造?
实际上,Foo<Bar>
的移动构造函数被定义为删除的,但请注意,被删除的隐式声明移动构造函数会被重载决议忽略。
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. Bar
和Foo<Bar>
之间的不同行为
请注意,Bar
的移动构造函数明确声明为deleted
,而Foo<Bar>
的移动构造函数是隐式声明并定义为deleted
。重点是删除的隐式声明移动构造函数会被重载决议所忽略,这使得可以使用其复制构造函数移动构造Foo<Bar>
。但是显式删除的移动构造函数将参与重载决议,意味着在尝试移动构造Bar
时,将选择已删除的移动构造函数,然后程序就会有错误。
这就是为什么Foo<Bar>
可以移动构造,而Bar
不能的原因。
标准文档对此有明确的说明。$12.8/11 复制和移动类对象
[class.copy]
已定义为删除的默认移动构造函数在重载决议中被忽略([over.match],[over.over])。[注:否则,删除的移动构造函数可能会干扰从rvalue初始化,该初始化可以使用复制构造函数。 ——注释结束]
卢浮宫里的名画
类? - einpoklum