gpt4 book ai didi

c++ - 预期 move_assignment 被删除

转载 作者:行者123 更新时间:2023-12-05 05:39:35 26 4
gpt4 key购买 nike

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

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 指出:

The implicitly-declared or defaulted move assignment operator for class T is defined asdeleted if any of the following is true:

  • T has a non-static data member that is const;
  • T has a non-static data member of a reference type;
  • T has a non-static data member that cannot be move-assigned (has deleted, inaccessible, or ambiguous move assignment operator);
  • T has direct or virtual base class that cannot be move-assigned (has deleted, inaccessible, or ambiguous move assignment operator).

A deleted implicitly-declared move assignment operator is ignored by overload resolution.

这让我相信,根据标准,确实应该删除移动赋值运算符(要点三)。我缺少什么,或者,如果可能的话,我如何在不手动输入所有可能的特化的情况下使包装类按预期工作?谢谢。

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;
}

最佳答案

您引用中的最后一句话“重载决策忽略了已删除的隐式声明的移动赋值运算符。”更准确地说:

A defaulted move assignment operator that is defined as deleted is ignored by overload resolution.

class.copy.assign

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

因此,重载决策会忽略此运算符。

因此,从右值赋值选择复制赋值。

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

关于c++ - 预期 move_assignment 被删除,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72645574/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com