繁体   English   中英

为什么移动构造函数会影响is_assignable?

[英]Why does move constructor affect is_assignable?

刚来自is_assignable和std :: unique_ptr @Angew告诉我,因为std::unique_ptr<int, do_nothing>std::unique_ptr<int>是不同的类型,所以static_assert(not std::is_assignable<std::unique_ptr<int>, std::unique_ptr<int, do_nothing>>::value, ""); 所以,我尝试过:

template<typename T, typename D>
struct MoveAssignOnly_V2
{
    MoveAssignOnly_V2&
    operator=(MoveAssignOnly_V2&)
        = delete;

    MoveAssignOnly_V2&
    operator=(MoveAssignOnly_V2&&) noexcept
    {}
};

int main()
{
      static_assert(not std::is_assignable_v<MoveAssignOnly_V2<int, float>,
                 MoveAssignOnly_V2<int, double>>);
}

是的,因为MoveAssignOnly_V2<int, float>MoveAssignOnly_V2<int, double>是两种不同的类型,因此它们不可分配。

但是 ,当我添加一个移动ctor:

template<class U, class E>
MoveAssignOnly_V2(MoveAssignOnly_V2<U, E>&& m) noexcept {}

static_assert失败! (包括gcc和clang)。

问题:为什么移动构造函数会影响is_assignable?

更新

我添加这个构造函数的原因是我发现std::unique_ptr有一个

template< class U, class E >
unique_ptr( unique_ptr<U, E>&& u ) noexcept;

,这让我有点困惑:如果它有这样一个ctor,它怎么可能不可分配? 所以我尝试将此类ctor添加到MoveAssignOnly_V2并发布此问题。 这两个答案很好,但是,仍然无法解释为什么当std::unique_ptr同时具有移动赋值和这个模板化构造函数时,它是不可赋值的。

拿这个代码:

MoveAssignOnly_V2<int, float> lhs;
MoveAssignOnly_V2<int, double> rhs;
lhs = stdL::move(rhs);

当转换构造函数(注意它不是移动构造函数)不存在时,无法将rhs分配给lhs

但是,当您添加构造函数模板时,现在有一种方法可以将rhs转换为MoveAssignOnly_V2<int, float> (它创建该类型的临时值)。 然后,可以从该临时值移动到lhs

这与以下原则相同:

double lhs = 3.14;
float rhs = 42.f;
lhs = std::move(rhs);

要解决问题中的更新:

您不能单独使用函数声明,您必须阅读完整的规范(在标准或合适的参考中 )。 引用有关std::unique_ptr的转换构造函数的链接引用:

如果满足以下所有条件,则此构造函数仅参与重载解析:

a) unique_ptr<U, E>::pointer可以隐式转换为pointer
b) U不是数组类型
c) Deleter是引用类型, E是与D相同的类型,或者Deleter不是引用类型, E可以隐式转换为D

正如您所看到的,必须实现unique_ptr的转换构造函数,以便只有在源删除器可以转换为目标删除器时才会激活它。 这与上一个问题中的移动分配基本相同。

你在这里添加的内容:

template<class U, class E>
MoveAssignOnly_V2(MoveAssignOnly_V2<U, E>&& m) noexcept {}

不仅是一个移动构造函数,而且是一个模板化的构造函数,可以从任何MoveAssignOnly_V2<U, E>构造MoveAssignOnly_V2<T, D> MoveAssignOnly_V2<U, E>

因此MoveAssignOnly_V2<int, float>MoveAssignOnly_V2<int, double>>构造MoveAssignOnly_V2<int, float>就可以了。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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