【问题标题】:Why is the move-constructor of std::optional not deleted when T is not move-constructible?当 T 不可移动构造时,为什么不删除 std::optional 的移动构造函数?
【发布时间】:2018-02-10 14:05:22
【问题描述】:

按照标准,std::optional<T>的拷贝构造函数:

...应定义为删除,除非is_copy_constructible_v<T>true

但是std::optional<T>的移动构造函数:

...除非is_move_constructible_v<T>true,否则不应参与重载决议。

作为我understand deleted constructors,不删除std::optional<T> 的移动构造函数的目的是允许这样的代码:

std::optional<X> o1;
std::optional<X> o2(std::move(o1));

...依靠一些转换序列来工作 - o2 将由使用 std::optional&lt;X&gt;&amp;&amp; 构造的 A 类型的对象构造(如果我错了,请纠正我)。

但是关于std::optional 的可能构造函数,我很难找出一个可以匹配这个用例的...

如果T 不可移动构造,为什么std::optional&lt;T&gt; 的移动构造函数根本没有删除

【问题讨论】:

    标签: c++ optional move-constructor


    【解决方案1】:

    显式删除它意味着它将是最好的匹配 x 值,因此会导致编译时错误,而不是 处理这些情况的复制构造函数。

    例如:

    #include <utility>
    
    struct X
    {
        X() = default;
        X(const X&) = default;
        X(X&&) = delete;
    };
    
    int main()
    {
        X a;
        X b(std::move(a));
    }
    

    这将导致类似:

    'X::X(X &&)': attempting to reference a deleted function
    

    显式删除的函数仍然参与重载 分辨率,并且可以是最佳匹配。这可能很有用, 例如,禁用某些转换。

    【讨论】:

    • 所以只有当T 可复制但不可移动时,才允许从x 值构造optional
    • @Holt:完全正确。
    • 如果T 不可移动构造,应该如何声明移动构造函数以将其从重载决议中排除?作为= default?
    • @MaartenBamelis 这取决于您如何实现optional - 由于某些限制,您不能(总是)将T 的实例直接存储到optional 对象中(特别是如果T不是默认可构造的),因此在optional 中使用= default 没有多大意义。您将不得不依赖类型特征和 SFINAE。
    • @MaartenBamelis:部分专业化可能是最好的,见this question
    【解决方案2】:

    委员会真的不关心可复制但不可移动的可憎之物。参见,例如,LWG issue 2768 的讨论,将此类类型描述为“病态”,而早期尝试将其支持为“疯狂”。

    这类东西的默认措辞通常是“不应参与重载决议”,除非有某些特殊原因来捕获调用(有时是适当的 - 例如,LWG issue 2766 - 但可能会导致不良副作用如LWG issue 2993)。对于复制特殊成员,这在概念之前根本无法做到,所以必须使用“定义为删除”。对于移动特殊成员OTOH,“定义为已删除”不够精确,因为“显式删除的移动”和“隐式定义为已删除的默认移动”之间存在巨大差异:后者不参与重载决议。

    另见LWG issue 2958的讨论。

    【讨论】:

      猜你喜欢
      • 2023-03-16
      • 2019-12-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多