std::variant编译报错:已删除函数使用问题的原因及修复咨询
关于std::variant与嵌套结构体默认初始化的编译错误问题
1. 报错原因
当结构体S的成员a带有=0的默认初始化时:
S的默认构造函数会被编译器合成为非平凡构造函数(需要执行代码将a初始化为0);- 由于
S是类C的私有嵌套结构体,std::variant<S>的默认构造函数需要调用S的非平凡构造函数,但std::variant模板无法访问C的私有成员S的构造逻辑,因此编译器会隐式删除std::variant<S>的默认构造函数; - 类
C的默认构造函数依赖所有成员的默认构造能力,因为test(std::variant<S>类型)无法默认构造,C的默认构造函数也被隐式删除,最终触发use of deleted function错误。
而移除a的默认初始化后:
S的默认构造函数变为平凡构造函数(编译器合成但不执行任何初始化操作,成员a处于未定义状态);std::variant<S>的默认构造函数也随之变为平凡构造,不需要显式调用S的构造函数,因此编译器可以正常生成C的默认构造函数,代码编译通过。
2. 保留默认初始化的修复方案
可以采用以下几种实用方式:
- 将
S设为public成员:让std::variant模板可以正常访问S的构造函数,从而生成合法的std::variant<S>默认构造函数,示例代码:class C { public: struct S { int a = 0; }; std::variant<S> test; }; - 显式定义
C的默认构造函数:手动初始化test成员,绕过std::variant<S>的默认构造限制,示例代码:class C { struct S { int a = 0; }; std::variant<S> test; public: C() : test(S{}) {} // 主动构造S实例并初始化variant }; - 为
S显式声明public默认构造函数:即使是默认合成的,也能确保std::variant可以访问(需配合S的访问权限调整,推荐直接设为public),示例代码:class C { public: struct S { int a = 0; S() = default; // 显式声明public默认构造 }; std::variant<S> test; };
3. 有无默认初始化的核心差异
| 状态 | S的默认构造类型 | std::variant<S>的默认构造能力 | C的默认构造生成情况 | 成员a的初始化状态 |
|---|---|---|---|---|
无=0默认初始化 | 平凡构造函数 | 可默认构造(平凡) | 可正常生成 | 未初始化(值未定义) |
有=0默认初始化 | 非平凡构造函数 | 默认构造被删除(无法访问S构造) | 被隐式删除 | 初始化为0 |
本质差异在于:平凡构造函数不需要执行显式的初始化逻辑,编译器可以直接通过内存操作完成构造,无需访问私有成员的构造接口;而非平凡构造函数需要执行代码逻辑,必须确保外部(如std::variant模板)有权限访问该构造逻辑,否则会导致依赖的类型无法默认构造。
内容的提问来源于stack exchange,提问作者Sir2B
相关产品推荐
相关产品推荐

