C++ 赋值运算符与值而非引用的分支
这个问题来自于委员会提出的问题 通常,我们将类型C++ 赋值运算符与值而非引用的分支,c++,c++11,language-lawyer,move-semantics,C++,C++11,Language Lawyer,Move Semantics,这个问题来自于委员会提出的问题 通常,我们将类型T的复制赋值运算符定义为T&operator=(const T&),将类型T的赋值运算符定义为T&operator=(T&&) 但是,当我们使用值参数而不是引用时会发生什么 class T { public: T& operator=(T t); }; 这将使复制和移动都可分配。然而,我想知道的是T的语言分支是什么 具体而言: 根据规范,这是否算作T的复制分配运算符 根据规范,这是否算作T的移动分配运算符 T是否有编译器生成的复制赋值
T
的复制赋值运算符定义为T&operator=(const T&)
,将类型T
的赋值运算符定义为T&operator=(T&&)
但是,当我们使用值参数而不是引用时会发生什么
class T
{
public:
T& operator=(T t);
};
这将使复制和移动都可分配。然而,我想知道的是T
的语言分支是什么
具体而言:
T
的复制分配运算符T
的移动分配运算符T
是否有编译器生成的复制赋值运算符T
是否有编译器生成的移动赋值运算符std::ismove\u assignable
其中大部分内容见§12.8。第17段定义了什么算作用户声明的复制分配运算符: 用户声明的复制赋值运算符
X::operator=
是类X
的非静态非模板成员函数,只有一个类型为X
、X&
、常量X&
、volatile X&
或常量volatile X&
的参数
第19段定义了用户声明的移动分配运算符:
用户声明的移动分配运算符X::operator=
是非静态的
类X
的非模板成员函数,只有一个参数
键入X&
,const X&
,volatile X&
,或const volatile X&
因此,它算作复制分配运算符,但不算作移动分配运算符
第18段说明编译器何时生成复制赋值运算符:
如果类定义没有显式声明副本赋值
运算符,则隐式声明一个。如果类定义声明
移动构造函数或移动赋值运算符,隐式
已声明的副本分配运算符定义为已删除;否则,
定义为默认值(8.4)。如果
类具有用户声明的复制构造函数或用户声明的
析构函数
第20段告诉我们编译器何时生成移动赋值运算符:
如果类X的定义没有显式声明移动
赋值运算符,如果
只有当[…]
-X没有用户声明的复制分配运算符,
[……] 由于类有一个用户声明的复制赋值运算符,编译器不会生成任何一个隐式运算符
std::is\u copy\u assignable
和std::is\u move\u assignable
在表49中被描述为分别具有与is\u assignable::value
和is\u assignable::value
相同的值。该表告诉我们,is_assignable::value
istrue
当:
表达式declval()=declval()
在处理时格式良好
作为未赋值的操作数(第5条)。访问检查按以下步骤执行:
如果在与T
和U
无关的上下文中。只有该文件的有效性
考虑赋值表达式的直接上下文
由于该类的declval()=declval()
和declval()=declval()
都是格式良好的,因此它仍然算作复制可分配和移动可分配
正如我在评论中提到的,奇怪的是,在存在移动构造函数的情况下,
operator=
将正确地执行移动,但从技术上讲不算作移动赋值操作符。更奇怪的是,如果类没有复制构造函数:它将有一个复制赋值操作符,它不进行复制,只进行移动。相关讨论:如果我同时拥有t&operator=(t t)和t&operator=(t&&t),则Visual Studio和g++都会出现编译器错误ambiguous@user929404:你应该这样做。关键是要将复制和移动赋值都替换为仅值赋值。