删除移动构造函数后C++列表初始化报错?如何恢复默认行为?
问题分析与解决
报错原因
- 聚合体身份丢失:原结构体
foo属于C++标准定义的聚合体,因此foo{42}可以通过聚合初始化直接对成员bar赋值,完全不需要依赖类的构造函数。但当你显式添加foo(foo&&) = delete;(哪怕是删除移动构造函数),foo就不再满足聚合体的判定条件——聚合体要求类/结构体不能存在任何用户声明的构造函数(包括删除的构造函数)。 - 默认构造函数被禁用:根据C++规则,只要类存在用户声明的构造函数(哪怕是删除的移动构造),编译器就不会自动生成默认构造函数。
- 无匹配构造函数可用:此时
foo{42}不再是聚合初始化,编译器会尝试寻找合适的构造函数创建临时对象,但foo既没有默认构造函数,也没有自定义的int参数构造函数,因此编译器报错(部分编译器会误报为找不到默认构造函数)。
恢复初始化的可行方案
方案1:显式定义int参数构造函数
直接为foo添加接受int的构造函数,适配foo{42}的初始化方式:
struct foo { int bar; foo(int b) : bar(b) {} foo(foo&&) = delete; };
此时const auto baz = foo{42};会通过这个自定义构造函数完成对象创建。
方案2:显式生成默认构造+指定初始化器(C++20+)
显式让编译器生成默认构造函数,同时使用C++20支持的非聚合体指定初始化器:
struct foo { int bar; foo() = default; // 显式要求编译器生成默认构造 foo(foo&&) = delete; }; // 使用指定初始化器直接赋值成员 const auto baz = foo{.bar=42};
方案3:直接使用指定初始化器(C++20+)
C++20允许对非聚合体的public成员使用指定初始化器,无需额外定义构造函数:
struct foo { int bar; foo(foo&&) = delete; }; // 直接指定成员初始化 const auto baz = foo{.bar=42};
方案4:保留聚合体属性(不删除移动构造)
如果不需要严格禁止移动,仅想保留原有的聚合初始化方式,可以删除foo(foo&&) = delete;,让foo继续作为聚合体,编译器会自动生成移动构造函数。若必须禁止移动,只能选择前面的方案。
内容的提问来源于stack exchange,提问作者Azad Salahli
相关产品推荐
相关产品推荐

