考虑以下示例:
#include <iostream>
#include <string>
#include <utility>
template <typename Base> struct Foo : public Base {
using Base::Base;
};
struct Bar {
Bar(const Bar&) { }
Bar(Bar&&) = delete;
};
int main() {
std::cout << std::is_move_constructible<Bar>::value << std::endl; // NO
std::cout << std::is_move_constructible<Foo<Bar>>::value << std::endl; // YES. Why?!
}
为什么编译器会生成一个移动构造函数,尽管基类是不可移动构造的?
这是在标准中还是在编译器错误中?有可能“完美地传播”将结构从基类移动到派生类吗?
发布于 2016-08-25 15:30:53
因为:
定义为已删除的默认移动构造函数将被重载解析忽略。
(class.copy/11)
Bar
的move构造函数已显式删除,因此无法移动Bar
。但Foo<Bar>
的move构造函数在被隐式声明为默认成员后被隐式删除,原因是Bar
成员无法移动。因此,可以使用其复制构造函数移动Foo<Bar>
。
编辑:我还忘记提到一个重要事实,即继承构造函数声明(如using Base::Base
)不继承默认、复制或移动构造函数,这就是为什么Foo<Bar>
没有从Bar
继承显式删除的移动构造函数的原因。
发布于 2016-08-25 15:29:41
1. std::is_move_constructible
的行为
这是std::is_move_constructible的预期行为
这意味着使用复制构造函数,仍然可以从右值引用T&&
构造T
。而且Foo<Bar>
有一个Implicitly-declared copy constructor。
2. Foo<Bar>
的隐式声明的构造函数
为什么编译器会生成移动构造函数,尽管基类是不可移动构造的?
..。
3. Bar
Foo<Bar>
和之间的不同行为
重点在于,重载解析会忽略已删除的隐式声明的move构造函数,这使得使用其构造函数移动构造Foo<Bar>
成为可能。但是显式删除的move构造器将参与重载解决,这意味着当尝试移动构造器Bar
时,删除的move构造器将被选中,那么程序是错误的。
这就是为什么Foo<Bar>
是可移动构造的,而Bar
不是。
该标准对此有明确的声明。$12.8/11 Copying and moving class objects [class.copy]
定义为已删除的默认移动构造函数将被重载解析忽略(over.match,over.over)。注意:删除的move构造函数会干扰来自r值的初始化,而右值可以使用复制构造函数。-结束注释
https://stackoverflow.com/questions/39139087
复制相似问题