首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >预期move_assignment将被删除

预期move_assignment将被删除
EN

Stack Overflow用户
提问于 2022-06-16 12:07:28
回答 1查看 71关注 0票数 3

我试图编写一个包装类,它有条件地禁用四个特殊的成员函数(复制构造、移动构造、复制分配和移动分配),下面是我用于测试目的的快速草稿:

代码语言:javascript
复制
enum class special_member : uint8_t {
    copy_ctor, move_ctor,
    copy_asgn, move_asgn
};

template<typename MemberType, special_member...>
struct _disabled_wrapper {
public:
    constexpr _disabled_wrapper(MemberType type) : _type(type) {}

public:
    constexpr MemberType& unwrapped() { return _type; }
    constexpr const MemberType& unwrapped() const { return _type; }

private:
    MemberType _type;
};

template<typename MemberType, special_member ... Disables>
struct _disabled_wrapper<MemberType, special_member::copy_ctor, Disables...> 
{
private:
    using _parent_t = _disabled_wrapper<MemberType, Disables...>;

public:
    constexpr _disabled_wrapper(const _parent_t& parent) : _parent(parent) {}

    constexpr _disabled_wrapper(const _disabled_wrapper&) = delete;
    constexpr _disabled_wrapper(_disabled_wrapper&&) = default;
    constexpr _disabled_wrapper& operator=(const _disabled_wrapper&) = default;
    constexpr _disabled_wrapper& operator=(_disabled_wrapper&&) = default;

public:
    constexpr MemberType& unwrapped() { return _parent.unwrapped(); }
    constexpr const MemberType& unwrapped() const { return _parent.unwrapped(); }

private:
    _parent_t _parent;
};

template<typename MemberType, special_member ... Disables>
struct _disabled_wrapper<MemberType, special_member::move_ctor, Disables...>
{
public: //Todo: Make private post fix.
    using _parent_t = _disabled_wrapper<MemberType, Disables...>;

public:
    constexpr _disabled_wrapper(const _parent_t& parent) : _parent(parent) {}

    constexpr _disabled_wrapper(const _disabled_wrapper&) = default;
    constexpr _disabled_wrapper(_disabled_wrapper&&) = delete;
    constexpr _disabled_wrapper& operator=(const _disabled_wrapper&) = default;
    constexpr _disabled_wrapper& operator=(_disabled_wrapper&&) = default;

public:
    constexpr MemberType& unwrapped() { return _parent.unwrapped(); }
    constexpr const MemberType& unwrapped() const { return _parent.unwrapped(); }

private:
    _parent_t _parent;
};

template<typename MemberType, special_member ... Disables>
struct _disabled_wrapper<MemberType, special_member::copy_asgn, Disables...>
{
private: 
    using _parent_t = _disabled_wrapper<MemberType, Disables...>;

public:
    constexpr _disabled_wrapper(const _parent_t& parent) : _parent(parent) {}

    constexpr _disabled_wrapper(const _disabled_wrapper&) = default;
    constexpr _disabled_wrapper(_disabled_wrapper&&) = default;
    constexpr _disabled_wrapper& operator=(const _disabled_wrapper&) = delete;
    constexpr _disabled_wrapper& operator=(_disabled_wrapper&&) = default;

public:
    constexpr MemberType& unwrapped() { return _parent.unwrapped(); }
    constexpr const MemberType& unwrapped() const { return _parent.unwrapped(); }

private:
    _parent_t _parent;
};

template<typename MemberType, special_member ... Disables>
struct _disabled_wrapper<MemberType, special_member::move_asgn, Disables...>
{
private:
    using _parent_t = _disabled_wrapper<MemberType, Disables...>;

public:
    constexpr _disabled_wrapper(const _parent_t& parent) : _parent(parent) {}

    constexpr _disabled_wrapper(const _disabled_wrapper&) = default;
    constexpr _disabled_wrapper(_disabled_wrapper&&) = default;
    constexpr _disabled_wrapper& operator=(const _disabled_wrapper&) = default;
    constexpr _disabled_wrapper& operator=(_disabled_wrapper&&) = delete;

public:
    constexpr MemberType& unwrapped() { return _parent.unwrapped(); }
    constexpr const MemberType& unwrapped() const { return _parent.unwrapped(); }

private:
    _parent_t _parent;
};

除三种情况(<move_ctor, move_asgn><copy_ctor, move_asgn><copy_ctor, move_ctor, move_asgn>)外,上述代码功能正确。具体来说,下面代码中的断言失败了,这使我相信,在move_ctor部分专门化的_disabled_wrapper中,由于某些原因,默认的移动赋值运算符没有被删除,尽管它的非静态成员_parent的移动分配被删除了。cppreference.com声明:

如果下列任何一项都是正确的,则将类T的隐式声明或默认移动赋值操作符定义为已删除:

  • T具有非静态数据成员,即const;
  • T具有参考类型的非静态数据成员;
  • T有一个不能移动的非静态数据成员(已删除、不可访问或不明确的移动赋值操作符);
  • T具有不能移动分配的直接或虚拟基类(已删除、不可访问或不明确的移动赋值运算符)。

重载解析忽略已删除的隐式声明的移动赋值运算符。

这使我相信,根据标准,移动赋值操作符确实应该删除(第三点)。我遗漏了什么,或者,如果可能的话,如何使包装类按照预期的方式工作,而无需手动输入所有可能的专门化?谢谢。

代码语言:javascript
复制
int main() {
    using type = _disabled_wrapper<int, special_member::move_ctor, special_member::move_asgn>;

    //Passes, hence member variable has its move_assignment deleted as intended.
    static_assert(std::is_move_assignable_v<type::_parent_t> == false); 
    //Fails here! Move assignment defined?
    static_assert(std::is_move_assignable_v<type> == false); 

    return 0;
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-06-16 16:51:34

引用中的最后一条语句“已删除、隐式声明的移动赋值运算符被重载解析忽略”。更准确地说:

被定义为已删除的默认移动赋值运算符将被重载解析忽略。

class.copy.assign

type有一个默认的移动赋值操作符,它被定义为已删除,因为它在基类中被删除。

因此,重载解析忽略了这个操作符。

因此,来自rvalue的赋值选择复制分配。

因此,type是可移动的,因为它是可复制的。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72645574

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档