boost :: variant处理仅移动类型的奇怪行为

344*_*442 3 c++ boost c++17

鉴于以下内容:

#if __cplusplus >= 201703L
    #include <variant>
    using std::variant;
#else
    #include <boost/variant.hpp>
    using boost::variant;
#endif
Run Code Online (Sandbox Code Playgroud)

考虑一下这个片段.这可以在c ++ 17 std::variant<>boost::variant<>.

struct B
{
    B() = default;
    B(const B&) = delete;
    B(B&&) {}
    B& operator=(const B&&) = delete;
    B& operator=(B&&) {}
};

int main()
{
    variant<B, int> v;
    v = B{};
}
Run Code Online (Sandbox Code Playgroud)

但是,这个其他示例仅使用C++ 17编译std::variant<>,因为boost::variant<>尝试执行复制分配.

struct A
{
    A(int) {}
};

struct B
{
    B(int) {}
    B(const B&) = delete;
    B(B&&) {}
    B& operator=(const B&) = delete;
    B& operator=(B&&) {}
};

int main()
{
    variant<A, B> v{A{42}};
    v = B{42}; // This line doesn't compile with Boost
}
Run Code Online (Sandbox Code Playgroud)

这两个例子之间唯一值得注意的区别是存在struct A和默认构造函数与构造函数的关系int.我还发现,如果class B在第二种情况下移动构造函数和赋值运算符= default,则可以使用Boost编译它.我做错了什么,或者这是Boost.Variant的问题?尝试使用Boost 1.65和GCC 7.2.0的两个示例.

seh*_*ehe 5

问题是move-constructor不是noexcept,这使得它不合适:

https://godbolt.org/g/368cjJ

B(B&&) noexcept {};
Run Code Online (Sandbox Code Playgroud)

你也可以写:

B(B&&) = default;
Run Code Online (Sandbox Code Playgroud)

在这种情况下,编译器隐式生成noexcept移动构造函数.

  • @ 3442因为已经确定`std :: variant`可能变成[`valueless_by_exception`](http://en.cppreference.com/w/cpp/utility/variant/valueless_by_exception),所以非``noexcept`移动构造函数是合适的. (5认同)