预期的move_assignment将被删除
我正在尝试编写一个有条件禁用四个特殊成员功能的包装类类(复制构造,移动构造,复制分配和移动分配),以下是我用于测试目的的快速草稿:
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;
};
正确的代码函数,除了三个案例(&lt; move_ctor,move_asgn&gt;
,&lt; copy_ctor,move_asgn&gt;
and &lt; copy_ctor,move_ctor,move_as_asgn&gt;
)。具体来说,以下代码中的断言失败了,这使我相信,由于某种原因,默认的移动分配运算符未删除,在move_ctor
_disabled_wrapper
,move_ctor
中即使其非静态成员_Parent
的移动分配已删除。 cppreference.com指出:
隐式指定或默认的移动分配运算符,定义为 如果以下任何一个是正确的:
删除
- t具有const;
的非静态数据成员- t具有参考类型的非静态数据成员;
- t有一个无法移动的非静态数据成员(已删除,无法访问或模棱两可的移动分配运算符);
- t具有无法移动的直接或虚拟基类(已删除,无法访问或模棱两可的移动分配操作员)。
超载分辨率忽略了隐式删除的移动分配运算符。
这使我相信,根据标准,应删除移动任务运算符(子弹点三)。我缺少什么,或者,如果可能的话,如何使包装类班级按预期工作,而无需手动输入所有可能的专业知识?谢谢。
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;
}
I'm trying to write a wrapper class that conditionally disables four special member functions (copy construct, move construct, copy assignment and move assignment), below is a quick draft I used for testing purposes:
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;
};
The above code functions correctly, except for three cases (<move_ctor, move_asgn>
, <copy_ctor, move_asgn>
and <copy_ctor, move_ctor, move_asgn>
). Specifically, the assertion in the code below fails, which leads me to believe that for some reason the defaulted move assignment operator is not deleted, in the move_ctor
partial specialisation of _disabled_wrapper
, even though its non-static member _parent
has its move assignment deleted. cppreference.com states:
The implicitly-declared or defaulted move assignment operator for class T is defined as
deleted 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.
Which makes me believe that, according to the standard, the move assignment operator should indeed be deleted (bullet point three). What am I missing and or, if possible, how do I make the wrapper class work as intended without manually typing all possible specialisations? Thank you.
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;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您的报价中的最后一个语句“被超载分辨率忽略了隐式删除的移动分配运算符”。更精确:
class.copy.copy.assign
类型具有默认的移动分配运算符,该操作员被定义为删除,因为它在基类中删除。
因此,超载分辨率忽略了该操作员。
因此,来自RVALUE的分配选择复制分配。
因此,
类型
是可以分配的,因为它是可复制的。The last statement in your quote "A deleted implicitly-declared move assignment operator is ignored by overload resolution." is more precisely:
class.copy.assign
type
has a defaulted move assignment operator which is defined as deleted because it is deleted in a base class.Therefore, this operator is ignored by overload resolution.
Therefore, assignment from an rvalue selects copy assignment.
Therefore,
type
is move assignable because it is copy assignable.