表达式 是由 运算符 和它们的操作数构成的序列,它指定了一项计算。对表达式求值可以产生一个结果或产生一些 副作用 。
什么是副作用(side-effect)?
副作用指的是在对表达式求值时对某些东西(比如存储在变量中的值)进行了修改。改变计算机存储单元里的数据或输入输出操作都算副作用。
运算符
运算符是一种告诉编译器执行特定的数学或逻辑操作的符号。常见的运算符有:
- 算数运算符
- 逻辑运算符
- 比较运算符
- 自增/自减运算符
- 赋值运算符
- 成员访问运算符
- 其他运算符
除了这些运算符外还有一些特殊的运算符,包括转换运算符、内存分配运算符等。
同时,因为任何运算符的操作数也是其他的表达式。而最基本的表达式,即不包含任何嵌套的表达式被称为 初等表达式(Primary expressions)。
初等表达式
初等表达式 有以下类型:
- this 指针
- 字面量(Literals)
- 标识表达式(Id-expressions)
- lambda 表达式(Lambda-expressions)(C++11 起)
- 折叠表达式(Fold-expressions)(C++17 起)
- requires 表达式(Requires-expressions)(C++20 起)
这些基本的表达式构成了运算符的操作数,又与运算符作为表达式构成了其他运算符的表达式。比较特殊的是,括号中的任何表达式也被归类为初等表达式,这保证了括号具有比任何运算符更高的优先级。
不求值表达式
部分特殊的运算符只查询它们的操作数的编译期性质,而不对作为操作数的表达式进行求值操作。作为操作数的表达式就是 不求值表达式(Unevaluated expressions)。例如 std::size_t n = sizeof(std::cout << 42);
这句代码就不会在控制台输出。
在 C++14 之后新增了一个特性,不求值表达式会被认为是一个 完整表达式 ,即便它们在语法上是某个更大的表达式的操作数也是如此。这条特性意味着什么?
什么是完整表达式(full-expression)?
完整表达式是指不是任何另一个表达式的子表达式的表达式。
在 C++20 后,requires 表达式也是不求值表达式了。
弃值表达式
将表达式求值得出的值舍去只用来实施其副作用的表达式被称为 弃值表达式(Discarded-value expressions)。所有的表达式语句的完整表达式都是弃值表达式。
弃值表达式的计算结果永远不会进行数组到指针和函数到指针转换,除非该表达式拥有特定的形式。