【问题标题】:Strange behavior in boost::variant's handling of move-only typesboost::variant 处理只移动类型的奇怪行为
【发布时间】:2017-11-27 15:52:00
【问题描述】:

鉴于以下情况:

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

考虑一下这个 sn-p。这在 c++17 的 std::variant&lt;&gt;boost::variant&lt;&gt; 下编译。

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{};
}

但是,这个其他示例仅使用 C++17 的 std::variant&lt;&gt; 编译,因为 boost::variant&lt;&gt; 尝试执行复制分配。

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
}

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

【问题讨论】:

  • 编译fine?
  • @Yuushi 是的,这真的很奇怪。如果你 = default 移动构造函数,它会编译,但 otherwise, it doesn't
  • 也许一些 MPL 魔法底层 Boost.Variant 正在检查琐碎的移动构造函数/赋值运算符,而非平凡的也应该被接受?
  • 问题是什么?目前它看起来像是向 Boost.Variant 报告的缺陷。
  • @ÖöTiib:我打算将此作为一个错误报告给 Boost 跟踪器,但决定提前在这里询问它是否实际上是一个错误,或者这是以某种方式记录的行为。

标签: c++ boost c++17


【解决方案1】:

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

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

B(B&&) noexcept {};

你也可以写:

B(B&&) = default;

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

【讨论】:

  • 那么,对于只移动类型,它的move-constructor/move-operator= 必须是noexcept 才能让variant 接受它?为什么std::variant 可以没有这个要求?
  • @3442 因为已经决定std::variant 可以变成valueless_by_exception,所以非noexcept 移动构造函数是合适的。
  • 谢谢@Quentin:是的。换句话说,Boost 的never-empty-guarantee 意味着移动构造必须noexcept
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-10
  • 2016-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多