std::variant 的编译器错误 - 使用已删除函数错误

Sir*_*r2B 6 c++ c++17 std-variant

我有一个类 C,其中包含一个 struct S 和一个 std::variant 作为成员。struct S 有一个 int 成员 a,初始化为 0。代码如下:

#include <variant>

class C
{
    struct S {
        int a = 0;
    };
    std::variant<S> test;
};


int main()
{
    C ctest;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

当我尝试使用 gcc 12.2.1(也使用不同的编译器)编译此代码时,出现以下错误:

#include <variant>

class C
{
    struct S {
        int a = 0;
    };
    std::variant<S> test;
};


int main()
{
    C ctest;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

您可以在此处查看代码和错误消息: https: //onlinegdb.com/ZdfGp9avn

但是,如果我从结构 S 中删除默认赋值 =0,则代码编译时不会出现错误。为什么会发生这种情况?如何在不删除默认分配的情况下修复此错误?在这种情况下,有默认分配与没有默认分配有什么区别?

Art*_*yer 5

S在完整类上下文之前不可默认构造,因为非静态数据成员初始值设定项的定义尚不可用(仅成员的声明)。

这意味着当std::variant<S>尝试计算是否S默认可构造时,编译器拥有的只是struct S { int a = ???; }. 它不知道编译器生成的默认构造函数是否应该抛出,因为它不知道 的a初始化程序是否抛出。

修复方法是使用手动说明符指定它noexcept

class C
{
    struct S {
        int a = 0;
        S() noexcept = default;
        // Or `S() noexcept(false) = default;` if it isn't noexcept
    };
    std::variant<S> test;
};
Run Code Online (Sandbox Code Playgroud)

或者将类型移出,以便在使用时完整:

struct S {
    int a = 0;
};

class C {
    using S = ::S;
    std::variant<S> test;
};
Run Code Online (Sandbox Code Playgroud)