Dmi*_*try 57 c++ language-lawyer move-constructor move-semantics c++11
请考虑以下示例:
#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?!
}
Run Code Online (Sandbox Code Playgroud)
尽管基类是不可移动构造的,为什么编译器会生成移动构造函数?
这是标准还是编译器错误?是否有可能"完美地传播"将构造从基础移动到派生类?
Bri*_*ian 30
因为:
重载解析会忽略定义为已删除的默认移动构造函数.
([class.copy]/11)
Bar的移动构造函数被明确删除,因此Bar无法移动.但由于无法移动成员,因此隐式声明默认情况下隐式删除了Foo<Bar>移动构造函数.因此可以使用其复制构造函数移动.BarFoo<Bar>
编辑:我也忘了提到一个重要的事实,即继承构造函数声明,如using Base::Base不继承默认,复制或移动构造函数,这就是为什么Foo<Bar>没有显式删除的移动构造函数继承自Bar.
son*_*yao 24
1.的行为 std::is_move_constructible
这是std :: is_move_constructible的预期行为:
没有移动构造函数但带有接受
const T&参数的复制构造函数的类型满足std::is_move_constructible.
这意味着使用复制构造函数,仍然可以T从rvalue引用构造T&&.并且Foo<Bar>有一个隐式声明的复制构造函数.
2.隐式声明的移动构造函数 Foo<Bar>
尽管基类是不可移动构造的,为什么编译器会生成移动构造函数?
实际上,移动构造函数Foo<Bar>被定义为已删除,但请注意,重载解析会忽略已删除的隐式声明的移动构造函数.
类的隐式声明或默认移动构造函数
T被定义为删除以下任何一种情况:Run Code Online (Sandbox Code Playgroud)... T has direct or virtual base class that cannot be moved (has deleted, inaccessible, or ambiguous move constructors); ...重载解析会忽略已删除的隐式声明的移动构造函数(否则会阻止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的初始化,而rvalue可以使用复制构造函数. - 结束说明]
| 归档时间: |
|
| 查看次数: |
2049 次 |
| 最近记录: |