附录

附录 A 单一定义规则

A.1 翻译单元

A.2 声明和定义

A.3 单一定义规则细节

A.3.1 对每个程序的约束

A.3.2 对每个翻译单元的约束

A.3.3 跨翻译单元对等约束

附录 B 值类别

表达式是 C++ 语言的基石,它提供了表达计算的主要机制。每个表达式都有一个类型,它描述了其计算产生的值的静态类型。表达式7具有类型int,表达式5 + 2也是,表达式x也是,如果变量x的类型是int。每一个表达式还有一个值类别,它描述了值是如何形成的,并影响表达式的行为。

B.1 传统的左值和右值

历史上,曾经只有两种值类别:即左值和右值。左值是引用存储在内存或机器寄存器中的实际值的表达式,例如表达式x,其中x是变量的名称。这些表达式可以修改,允许更新存储的值。例如,如果xint类型的变量,下面的赋值将把x的值替换为7

x = 7;

术语左值来源于这些表达式在赋值操作中可能扮演的角色:字母“l”代表“左手边”,因为(历史上,在 C 语言中)只能在赋值操作的左手边出现左值。相反,右值(“r”代表“右手边”)只能出现在赋值表达式的右侧。

然而,当 C 语言在 1989 年标准化时,情况发生了变化:虽然int const仍然是存储在内存中的值,但它不能出现在赋值操作的左侧:

int const x; // x 是一个不变的左值
x = 7; // ERROR: 可修改的左值才能在左侧

C++ 做了进一步的改变:类的右值可以出现在赋值的左边。这种赋值实际上是对类的适当赋值操作符的函数调用,而不是对标量类型的“简单”赋值,因此它们遵循成员函数调用的(单独的)规则。

由于所有这些变化,术语左值现在有时表示可本地化的值。引用变量的表达式并不是左值表达式的唯一类型。另一类左值表达式包括指针解引用操作(例如 *p),它指向存储在指针引用的地址上的值,以及指向类对象成员的表达式(例如:p->data)。即使调用返回用 & 声明的“传统”左值引用类型的值的函数也是左值。例如(详情见 679 页 B.4 节):

std::vector<int> v;
v.front(); // 仍然是左值,因为返回类型是一个左值引用

也许令人惊讶的是,字符串字面值也是(不可修改的)左值。

右值是纯数学值(如7或字符'a'),不一定有任何相关的存储空间:它们的存在是为了计算的目的,但是一旦它们被使用,就不能再被引用。特别是,除了字符串字面值(例如:7'a'truenullptr)之外的任何文字值都是右值,许多内置算术计算的结果(例如:整数类型xx + 5)和调用按值返回结果的函数也是右值。也就是说,所有临时值都是右值。(但这不适用于引用它们的命名引用。)


http://example.com/2023/08/15/cpp-template-ch/cpp-template-ch29/
作者
QiDianMaker
发布于
2023年8月14日
更新于
2023年8月14日
许可协议