为什么添加移动构造函数禁用初始化列表
why does adding a move constructor disable initializier list?
使用简单的struct
,例如
struct Foo { int i; };
我可以使用初始器列表创建一个新实例;无需编写构造函数:
Foo foo { 314 };
如果我现在添加一个移动构造函数
struct Bar
{
int i;
Bar(Bar&& other) { i = other.i; }
};
初始化器不再工作,我也必须添加一个构造函数:
Bar(int i) : i(i) {}
我猜想这种行为与此答案有些相关(对于用户定义的移动 - 构建体禁用隐式复制构建器吗?),但是更多的详细信息会很好。
编辑:如答案所示,这与添加构造函数有关。如果我只是添加一个移动操作员,那似乎会造成各种不一致的情况:
struct Baz
{
int i;
Baz& operator=(Baz&& other)
{
this->i = other.i;
return *this;
}
};
初始化器再次起作用,尽管"移动"的语法略有不同(是的,这实际上是默认的构造和移动分配;但最终结果似乎大致相同):
Baz baz{ 3141 };
Baz b;
b = std::move(baz);
当没有构造函数时,此语法是汇总初始化,因为此结构是 gentregate 。。
添加构造函数后,该结构不再是 contregate ,汇总初始化无法使用。确切的规则在列表初始化中列出,相关规则是:
T型对象的列表初始化的效果为:
- 否则,如果t是骨料类型,则执行聚合初始化。
- 否则,在两个阶段考虑T的构造函数:...
不是初始化器列表由移动构造函数所禁用的构建(从那里开始),而是汇总构造。出于一个充分的理由:通过添加自定义构造函数,我们向编译器说明中的类不是汇总中的类,而不仅仅是一个不同的成员在每个成员上进行操作。
对于汇总,即使成员变量具有非平凡类型,默认默认值,复制和移动构造函数也将很好地工作。如果不能将其委派给它们,则将自动删除副本构造,而Move Construction可用:
struct A { // non-copyable
int a;
int b;
A(int a_, int b_): a(a_), b(b_) { std::cout << "A(int,int)n"; }
A() { std::cout << "A()n"; }
A(const A&) = delete;
A(A&&) { std::cout << "A(A&&)n"; }
};
struct B {
A a;
};
int main() {
B b1{{1,2}}; // OK: aggregate
B b2{std::move(b1)}; // OK: calls A::A(A&&)
//B b3{b1}; // error: B::B(const B&) auto-deleted
}
但是,如果您想出于某些其他原因删除复制构造并将其他构造默认保留,请明确说明:
struct A { // copyable
int a;
int b;
A(int a_, int b_): a(a_), b(b_) { std::cout << "A(int,int)n"; }
A() { std::cout << "A()n"; }
A(const A&) { std::cout << "A(const A&)n"; }
A(A&&) { std::cout << "A(A&&)n"; }
};
struct B { // non-copyable
A a;
B() = default;
B(const B&) = delete;
B(B&&) = default;
};
int main() {
B b1{{1,2}}; // OK: still an aggregate
B b2{std::move(b1)}; // delegates to A::A(A&&)
//B b3{b1}; // error
}
因为您使用的是汇总初始化,其中说:
汇总初始化是列表限制的一种形式, 初始化汇总的聚合是以下类型之一:
的数组类型类类型(通常是结构或联合)
- 没有私人或受保护的非静态数据成员
- 没有用户提供, 继承或显式(自C 17)构造函数(明确 允许默认或删除的构造函数)(因为C 11)
- 否 虚拟,私人或受保护(自C 17)基类
- 没有虚拟的 成员功能
点2使您的情况失败。
相关文章:
- C++类 - 初始化列表 - 递归 - 按值传递
- 在初始化列表之外手动调用基类的构造函数
- C++:带有大括号初始化列表的函数调用表达式 - 标准是否规定在单个元素列表的微不足道的情况下忽略大括号?
- std::map与谓词与初始化列表
- 类内初始化与构造函数初始化列表的顺序
- 当返回语句时,逗号运算符、大括号初始化列表和 std::unique_ptr 组合在一起
- 使用初始化列表填充C++中的多维结构数组时出现问题
- 如何在初始化列表中的构造函数之后初始化变量/对象?
- C++初始化列表与分配值
- C++初始化列表中的向量集大小或调整大小
- 在构造函数初始化列表中使用 std::variant
- emplace_back初始化列表错误,当初始化列表在独立变量上工作时
- 解释了构造函数成员初始化列表
- 使用初始化列表时如何获取私有数据?
- 用初始化列表和超类构造函数声明子类构造函数的正确方式
- 如何在成员初始化列表中声明共享指针
- 庞大的初始化列表,如何修复"fatal error C1060: compiler is out of heap space"
- 我可以检查初始化列表中设置的构造函数主体中的变量吗
- 使用整数初始化列表初始化长双精度的向量
- 是否可以在C++中使用初始化列表设置数组的特定成员?