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

时间:2017-09-01 13:31:57

标签: c++ optional move-constructor

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

  除非is_copy_constructible_v<T>true,否则

...将被定义为已删除。

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

  

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

在我understand deleted constructors时,不删除std::optional<T>的move-constructor的目的是允许这样的代码:

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

...依靠某些转化顺序工作 - o2将由A类型的对象构建,该对象使用std::optional<X>&&构建(如果我错了,请更正我) )。

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

如果std::optional<T>不能移动构建,为什么T的移动构造函数根本不会删除

2 个答案:

答案 0 :(得分:11)

明确删除它意味着它将是最佳匹配 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

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

答案 1 :(得分:4)

委员会真的不关心可复制但不可移动的可憎之事。例如,参见LWG issue 2768的讨论,其中将这种类型描述为“病态的”,以及早先将其称为“疯狂”的尝试。

这种东西的默认措辞一般是“不应参与重载决策”,除非有一些特殊的理由来捕获呼叫(有时候是合适的 - 例如LWG issue 2766 - 但是会导致不合需要的副作用,如LWG issue 2993)。对于复制特殊成员,在概念之前根本无法完成,因此必须使用“定义为已删除”。对于移动特殊成员,OTOH“定义为删除”不够精确,因为“明确删除的移动”和“隐式定义为删除的默认移动”之间存在巨大差异:后者不参与重载解析。

另见LWG issue 2958的讨论。