3 回答
TA贡献1783条经验 获得超4个赞
移动构造函数和赋值运算符的隐式生成一直存在争议,并且在最近的C ++标准草案中进行了重大修订,因此目前可用的编译器在隐式生成方面可能表现不同。
有关该问题的更多信息,请参阅2010 WG21论文列表并搜索“mov”
目前的规范(N3225,从11月开始)规定(N3225 12.8 / 8):
如果类的定义
X
没有显式地声明一个移动构造函数,那么当且仅当一个类的定义被隐式声明为默认值时
X
没有用户声明的复制构造函数,和
X
没有用户声明的复制赋值运算符,
X
没有用户声明的移动赋值运算符,
X
没有用户声明的析构函数,和移动构造函数不会被隐式定义为已删除。
中有类似的语言,指定何时将移动赋值运算符隐式声明为默认值。您可以找到完整的更改列表,以支持N3203中隐式移动生成的当前规范:收紧生成隐式移动的条件 ,这主要基于Bjarne Stroustrup的论文N3201提出的一个解决方案:向右移动。
TA贡献1872条经验 获得超3个赞
隐式生成的移动构造函数已被考虑用于标准,但可能是危险的。见Dave Abrahams的分析。
但是,最后,标准确实包括隐式生成移动构造函数和移动赋值运算符,尽管有相当多的限制列表:
如果类X的定义没有显式声明一个移动构造函数,那么当且仅当
-X没有用户声明的复制构造函数时,将隐式声明一个默认值,
- X没有用户声明的复制赋值运算符,
- X没有用户声明的移动赋值运算符,
- X没有用户声明的析构函数,并且
- 移动构造函数不会被隐式定义为已删除。
但这并不是故事的全部内容。可以声明ctor,但仍定义为已删除:
隐式声明的复制/移动构造函数是其类的内联公共成员。如果X具有以下内容,则将类X的默认复制/移动构造函数定义为已删除(8.4.3):
- 具有非平凡对应构造函数的变体成员,X是类似联合的类,
- 类型为M(或其数组)的非静态数据成员,由于重载解析(13.3)而无法复制/移动,如应用于M的相应构造函数,导致歧义或从默认构造函数中删除或无法访问的函数,
- 由于重载解析(13.3)而无法复制/移动的直接或虚拟基类B,应用于B的相应构造函数,导致歧义或从默认构造函数中删除或无法访问的函数,
- 具有从默认构造函数中删除或无法访问的析构函数的任何直接或虚拟基类或非静态数据成员,
- 对于复制构造函数,rvalue引用类型的非静态数据成员,或
- 对于移动构造函数,是非静态数据成员或直接或虚拟基类,其类型不具有移动构造函数,并且不是非常简单的可复制。
TA贡献1829条经验 获得超9个赞
(至于现在,我正在研究一个愚蠢的宏......)
是的,我也走了那条路。这是你的宏:
// detail/move_default.hpp#ifndef UTILITY_DETAIL_MOVE_DEFAULT_HPP#define UTILITY_DETAIL_MOVE_DEFAULT_HPP#include <boost/preprocessor.hpp>#define UTILITY_MOVE_DEFAULT_DETAIL_CONSTRUCTOR_BASE(pR, pData, pBase) pBase(std::move(pOther))#define UTILITY_MOVE_DEFAULT_DETAIL_ASSIGNMENT_BASE(pR, pData, pBase) pBase::operator=(std::move(pOther));#define UTILITY_MOVE_DEFAULT_DETAIL_CONSTRUCTOR(pR, pData, pMember) pMember(std::move(pOther.pMember))#define UTILITY_MOVE_DEFAULT_DETAIL_ASSIGNMENT(pR, pData, pMember) pMember = std::move(pOther.pMember);#define UTILITY_MOVE_DEFAULT_DETAIL(pT, pBases, pMembers) \ pT(pT&& pOther) : \ BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM( \ UTILITY_MOVE_DEFAULT_DETAIL_CONSTRUCTOR_BASE, BOOST_PP_EMPTY, pBases)) \ , \ BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM( \ UTILITY_MOVE_DEFAULT_DETAIL_CONSTRUCTOR, BOOST_PP_EMPTY, pMembers)) \ {} \ \ pT& operator=(pT&& pOther) \ { \ BOOST_PP_SEQ_FOR_EACH(UTILITY_MOVE_DEFAULT_DETAIL_ASSIGNMENT_BASE, BOOST_PP_EMPTY, pBases) \ BOOST_PP_SEQ_FOR_EACH(UTILITY_MOVE_DEFAULT_DETAIL_ASSIGNMENT, BOOST_PP_EMPTY, pMembers) \ \ return *this; \ }#define UTILITY_MOVE_DEFAULT_BASES_DETAIL(pT, pBases) \ pT(pT&& pOther) : \ BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM( \ UTILITY_MOVE_DEFAULT_DETAIL_CONSTRUCTOR_BASE, BOOST_PP_EMPTY, pBases)) \ {} \ \ pT& operator=(pT&& pOther) \ { \ BOOST_PP_SEQ_FOR_EACH(UTILITY_MOVE_DEFAULT_DETAIL_ASSIGNMENT_BASE, BOOST_PP_EMPTY, pBases) \ \ return *this; \ }#define UTILITY_MOVE_DEFAULT_MEMBERS_DETAIL(pT, pMembers) \ pT(pT&& pOther) : \ BOOST_PP_SEQ_ENUM(BOOST_PP_SEQ_TRANSFORM( \ UTILITY_MOVE_DEFAULT_DETAIL_CONSTRUCTOR, BOOST_PP_EMPTY, pMembers)) \ {} \ \ pT& operator=(pT&& pOther) \ { \ BOOST_PP_SEQ_FOR_EACH(UTILITY_MOVE_DEFAULT_DETAIL_ASSIGNMENT, BOOST_PP_EMPTY, pMembers) \ \ return *this; \ }#endif
// move_default.hpp#ifndef UTILITY_MOVE_DEFAULT_HPP#define UTILITY_MOVE_DEFAULT_HPP#include "utility/detail/move_default.hpp"// move bases and members#define UTILITY_MOVE_DEFAULT(pT, pBases, pMembers) UTILITY_MOVE_DEFAULT_DETAIL(pT, pBases, pMembers)// base only version#define UTILITY_MOVE_DEFAULT_BASES(pT, pBases) UTILITY_MOVE_DEFAULT_BASES_DETAIL(pT, pBases)// member only version#define UTILITY_MOVE_DEFAULT_MEMBERS(pT, pMembers) UTILITY_MOVE_DEFAULT_MEMBERS_DETAIL(pT, pMembers)#endif
(我删除了真实的评论,这些评论是长度和纪录片。)
您可以将类中的基数和/或成员指定为预处理程序列表,例如:
#include "move_default.hpp"struct foo{ UTILITY_MOVE_DEFAULT_MEMBERS(foo, (x)(str)); int x; std::string str;};struct bar : foo, baz{ UTILITY_MOVE_DEFAULT_BASES(bar, (foo)(baz));};struct baz : bar{ UTILITY_MOVE_DEFAULT(baz, (bar), (ptr)); void* ptr;};
然后是一个移动构造函数和移动赋值运算符。
(顺便说一句,如果有人知道如何将细节组合成一个宏,那就会膨胀。)
- 3 回答
- 0 关注
- 585 浏览
添加回答
举报