简体   繁体   中英

Strange behavior in boost::variant's handling of move-only types

Given the following:

#if __cplusplus >= 201703L
    #include <variant>
    using std::variant;
#else
    #include <boost/variant.hpp>
    using boost::variant;
#endif

Consider this snippet. This compiles under both c++17's std::variant<> and 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{};
}

However, this other example only compiles with C++17's std::variant<> , since boost::variant<> attempts to perform a copy-assignment.

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
}

The only notable differences between the two examples are the presence of struct A and default constructors versus constructors taking an int . I have also found out that if the move constructor and assignment operator of class B in the second case are = default ed, it can be compiled using Boost. Am I doing something wrong or is this an issue with Boost.Variant? Both examples where attempted using Boost 1.65 and GCC 7.2.0.

The problem is that the move-constructor is not noexcept, which makes it unsuitable:

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

B(B&&) noexcept {};

You can also write:

B(B&&) = default;

in which case the compiler implicitly generates a noexcept move constructor.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM