xda*_*liu 3 c++ return-type rvalue lvalue assignment-operator
(注意原来的问题标题有“而不是右值”而不是“而不是常量引用”。下面的答案之一是对旧标题的回应。为了清楚起见,这是固定的)
C 和 C++ 中的一种常见构造是用于链式赋值,例如
int j, k;
j = k = 1;
Run Code Online (Sandbox Code Playgroud)
第二=首先进行,用该表达k=1具有副作用k被设置为1,而表达式本身的值是1。
但是,在 C++ 中合法(但在 C 中不合法)的一种构造如下,它对所有基本类型都有效:
int j, k=2;
(j=k) = 1;
Run Code Online (Sandbox Code Playgroud)
在这里,表达式j=k具有设置j为 2的副作用,并且表达式本身成为对 的引用j,然后将其设置j为 1。据我所知,这是因为表达式j=k返回非- const int&,例如一般来说是左值。
通常也建议将此约定用于用户定义的类型,如Meyers Effective C++中的“Item 10: Have assignment operators return a (non-const) reference to *this”中所述。本书的这一部分并没有试图解释为什么参考文献是非引用的const,甚至没有注意到const顺便提及的非引用性。
当然,这当然增加了功能,但(j=k) = 1;至少可以说这种说法似乎很尴尬。
如果约定改为使用内置赋值返回const引用,那么自定义类也将使用此约定,并且 C 中允许的原始链式构造仍然有效,无需任何无关的副本或移动。例如,以下正确运行:
#include <iostream>
using std::cout;
struct X{
int k;
X(int k): k(k){}
const X& operator=(const X& x){
// the first const goes against convention
k = x.k;
return *this;
}
};
int main(){
X x(1), y(2), z(3);
x = y = z;
cout << x.k << '\n'; // prints 3
}
Run Code Online (Sandbox Code Playgroud)
优点是所有 3 个(C 内置函数、C++ 内置函数和 C++ 自定义类型)都一致不允许(j=k) = 1.
在 C 和 C++ 之间添加这个习语是有意的吗?如果是这样,什么类型的情况会证明它的使用是合理的?换句话说,这种功能扩展提供了什么非虚假的好处?
按照设计,C 和 C++ 之间的一个根本区别是 C 是一种左值丢弃语言,而 C++ 是一种左值保留语言。
在 C++98 之前,Bjarne 添加了对该语言的引用,以使运算符重载成为可能。而引用,为了有用,需要保留表达式的左值而不是丢弃。
这种保留左值的想法直到 C++98 才真正正式化。在 C++98 标准之前的讨论中,引用要求保留表达式的左值的事实被注意到并形式化,这就是 C++ 与 C 做出重大而有目的的突破并成为左值保留语言的时候。
C++ 力求尽可能保留任何表达式结果的“左值”。它适用于所有内置运算符,也适用于内置赋值运算符。当然,不会启用像 那样的表达式(a = b) = c,因为它们的行为是未定义的(至少在原始 C++ 标准下)。但是由于 C++ 的这个特性,你可以编写如下代码
int a, b = 42;
int *p = &(a = b);
Run Code Online (Sandbox Code Playgroud)
它有多有用是一个不同的问题,但同样,这只是C++ 表达式的左值保留设计的一个结果。
至于为什么它不是const左值......坦率地说,我不明白为什么它应该是。与 C++ 中任何其他保留左值的内置运算符一样,它只保留赋予它的任何类型。