为什么当T不可移动构造时,std :: optional的move-constructor不会被删除?

Hol*_*olt 12 c++ optional move-constructor

根据标准,复制构造函数std::optional<T>:

......除非is_copy_constructible_v<T>是,否则应被定义为删除true.

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

......除非is_move_constructible_v<T>是,否则不得参与超载决议true.

据我了解删除的构造函数,不删除move-constructor的目的std::optional<T>是允许这样的代码:

std::optional<X> o1;
std::optional<X> o2(std::move(o1));
Run Code Online (Sandbox Code Playgroud)

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

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

为什么移动构造函数std::optional<T>根本不被删除,如果T不是可移动构造的?

sp2*_*nny 11

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

例如:

#include <utility>

struct X
{
    X() = default;
    X(const X&) = default;
    X(X&&) = delete;
};

int main()
{
    X a;
    X b(std::move(a));
}
Run Code Online (Sandbox Code Playgroud)

这将导致类似于:

'X::X(X &&)': attempting to reference a deleted function
Run Code Online (Sandbox Code Playgroud)

显式删除的功能仍然参与重载决策,并且可以是最佳匹配.例如,禁用某些转换可能非常有用.

  • @MaartenBamelis:部分专业化可能是最好的,参见[this question](/sf/ask/1895115771/) (2认同)

T.C*_*.C. 5

委员会确实不关心可复制但不可移动的令人厌恶的东西。例如,参见LWG 第 2768 期的讨论,该讨论将此类类型描述为“病态”,而早期尝试将其支持为“疯狂”。

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

另请参阅LWG 问题 2958的讨论。