表达式何时被正式求值?类类型表达式求值时机问询
表达式求值的时机与类类型表达式的求值规则
首先明确:你对表达式求值的理解是准确的——对表达式X求值,核心是完成值计算(确定表达式产生的结果,可能是左值、右值及其对应的值/标识),同时可能伴随副作用(比如修改对象状态、调用函数等)。而表达式是否会被求值,完全取决于它所处的语境,C++标准对不同语境下的求值行为有明确规定。
一、通用表达式求值的正式规则
求值的触发条件:
绝大多数语境下,表达式都会被求值,除非它是未求值操作数(unevaluated operand)——这类语境只需要确定表达式的类型,不需要计算值或执行副作用。典型的未求值语境包括:sizeof(expr)、typeid(expr)中的exprdecltype(expr)、decltype(auto)中的exprnoexcept(expr)中的expr- 模板参数中的表达式(除非实例化时需要求值)
求值的两个核心部分:
- 值计算:确定表达式的结果(比如左值对应对象的标识,右值对应具体的数值或临时对象)
- 副作用:表达式执行过程中对程序状态的修改(比如赋值、构造函数调用、修改全局变量等)
类类型表达式的求值特点:
类类型的表达式求值后通常是左值(比如命名对象a)或右值(比如临时对象S{})。当类类型表达式作为函数实参、初始化器、运算符操作数等时,会触发值计算;如果涉及到对象拷贝/移动,还会伴随对应的构造函数调用(副作用)。
二、针对你代码的具体分析
代码回顾:
struct S { int x = 42; int& ref; S(): ref(x) // 此上下文中表达式'ref'是否会被求值? { this->x = 10; // 此上下文中表达式'this'是否会被求值? }; }; int main() { S a{ }; S b{ a }; // 此上下文中表达式'a'是否会被求值? // 若是,该表达式'a'产生的值是什么? }
1. 初始化列表中的ref(x)
这里的ref不是表达式,而是被初始化的成员名称,不存在“求值”的说法。初始化列表的语法是成员(初始化表达式),真正被求值的是括号内的x:
x是当前正在构造的S对象的成员,作为左值被求值,值计算的结果是x的标识(即对象的成员变量本身),用来将ref绑定到x上。
2. 构造函数内的this->x = 10
this是隐式的指针参数(类型为S* const),属于左值表达式,这里会被求值:
this的求值是值计算,结果是当前正在构造的S对象的地址(指针值);随后通过->访问成员x,赋值操作=10是副作用,修改了x的值。
3. S b{a}中的a
a是类类型的左值表达式,会被求值:
a的值计算结果是左值,即对象a的标识(可以理解为指向a的“引用身份”);这里用a初始化b,会调用S的默认拷贝构造函数(编译器自动生成),a作为实参绑定到拷贝构造函数的const S&参数上——因为是传引用,不会触发对象拷贝,a的求值仅用于传递对象的标识。
内容的提问来源于stack exchange,提问作者user20175049
相关产品推荐
相关产品推荐

