为什么移动构造函数会影响is_assignable? [英] Why does move constructor affect is_assignable?

查看:105
本文介绍了为什么移动构造函数会影响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, "");.所以,我尝试了:

Just came from is_assignable and std::unique_ptr. @Angew tells me that because std::unique_ptr<int, do_nothing> and std::unique_ptr<int> are different types, so static_assert(not std::is_assignable<std::unique_ptr<int>, std::unique_ptr<int, do_nothing>>::value, "");. So, I tried:

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>是两种不同的类型,所以它们是不可分配的.

Yes, because MoveAssignOnly_V2<int, float> and MoveAssignOnly_V2<int, double> are two different types, so they are not assignable.

但是,当我添加移动ctor时:

But, when I add a a move ctor:

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

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

static_assert fail!(both gcc and clang).

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

Question here: Why does move constructor affects is_assignable?

我添加此构造函数的原因是我发现std::unique_ptr具有

The reason why I add this constructor is that I found std::unique_ptr have a

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

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

, which confuses me a little: how can it be not assignable now that it has such a ctor? so I tried add such ctor to MoveAssignOnly_V2 and post this question. The two answers are fine, however, still cannot explain why std::unique_ptr is not assignable when it has both move assignment and this templated constructor.

推荐答案

使用此代码:

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

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

When the converting constructor (note that it's not a move constructor) is not there, there is no way to assign rhs into lhs.

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

However, when you add the constructor template, there is now a way to convert rhs into the type MoveAssignOnly_V2<int, float> (which creates a temporary of that type). Then, it's possible to move-assign from that temporary into lhs.

这与以下相同:

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

要解决问题中的更新:

不能单独使用函数声明,而必须阅读完整的规范(在标准或

You cannot go with function declarations alone, you have to read the full specification (in the standard or suitable reference). Quoting the linked reference about the converting constructor of std::unique_ptr:

仅当满足以下所有条件时,此构造函数才参与重载解析:

This constructor only participates in overload resolution if all of the following is true:

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

a) unique_ptr<U, E>::pointer is implicitly convertible to pointer
b) U is not an array type
c) Either Deleter is a reference type and E is the same type as D, or Deleter is not a reference type and E is implicitly convertible to D

因此,如您所见,必须实现unique_ptr的转换构造函数,以便仅在源删除程序可以转换为目标删除程序时才起作用.这基本上与上一个问题中的移动分配规则相同.

So as you can see, the unique_ptr's converting constructor must be implemented so that it's only active if the source deleter can be converted to the target one. That's basically the same rule as for move assignment in the previous question.

这篇关于为什么移动构造函数会影响is_assignable?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆