gcc8/9中std::variant需默认构造函数,gcc10/Clang无此要求的编译问题
结论:这是 GCC 8.x/9.x 的编译器 Bug,你的代码本身符合 C++ 标准
首先咱们拆解下你遇到的核心矛盾:编译器报错说访问了Foo::Foo()这个私有构造函数,但你的代码里根本没有任何地方需要默认构造Foo、Boo或者std::variant<Foo, Boo>——外层的std::variant是用std::string初始化的,内层的variant<Foo,Boo>也只在模板函数里通过带参构造创建实例,完全碰不到默认构造的逻辑。
问题根源
这是 GCC 8.x 和 9.x 版本中std::variant实现的一个缺陷:当实例化嵌套的std::variant<std::variant<Foo,Boo>, std::string>时,编译器错误地触发了对内层variant<Foo,Boo>的默认构造能力检查(具体是std::is_nothrow_default_constructible的实例化),而这个检查过程中,编译器没有正确尊重Foo/Boo默认构造函数的私有属性,导致了错误。
GCC 7.x 和 10.x 没有这个问题,说明 GCC 团队在后续版本中修复了std::variant类型 trait 检查的逻辑,同时旧版本的实现也未引入这个错误。
为什么移除模板或main代码后就正常?
- 移除
template<bool X>后,编译器不会触发某个触发错误检查的模板实例化路径; - 移除main里的外层
variant代码,自然不会触发对内层variant的错误检查逻辑,编译就恢复正常了。
临时解决办法(针对 GCC 8/9)
如果你暂时无法升级或降级编译器,可以尝试:
- 若业务允许,给
Foo和Boo添加一个public的默认构造函数(哪怕标记为= delete,这样is_default_constructible会返回false,但编译器不会触发私有访问错误); - 调整外层
variant的使用方式,比如用std::make_variant显式指定初始化类型,避免触发错误的 trait 检查。
内容的提问来源于stack exchange,提问作者fghj
相关产品推荐
相关产品推荐

