为何非constexpr对象s可初始化constexpr变量,指针p却不行?
核心规则:C++常量表达式求值时,禁止读取非constexpr变量的值,但对于非constexpr对象的直接调用或其地址的临时使用(只要不依赖该地址的实际值),在特定条件下是允许的。
分情况拆解:
auto constexpr x{s.func()}合法:func()是constexpr成员函数,且函数体完全不依赖对象s的任何状态(直接返回常量42)。虽然s不是constexpr对象,但调用这个const成员函数时,编译器不需要获取s的具体地址或状态就能计算出结果,因此符合常量表达式的要求。auto constexpr y{(&s)->func()}合法:&s是取局部对象的地址,虽然这个地址本身是运行时确定的,但调用func()时同样不需要用到该地址的实际值(函数没访问对象成员)。编译器可以直接忽略地址的具体值,直接计算出func()的返回结果,因此不会触发常量表达式的限制。auto constexpr z{p->func()}非法:p是一个非constexpr的指针变量,常量表达式求值过程中不允许读取非constexpr变量的值——哪怕p指向的是s,编译器也无法在编译期保证p的值是固定不变的(比如理论上后续代码可能修改p)。读取p的值这一步本身就违反了常量表达式的规则,因此报错。
总结来说,关键区别在于:前两种情况没有读取非constexpr变量的值(s的调用没用到其地址/状态,&s是临时表达式且未被读取存储),而第三种情况必须读取p这个变量的值,这是常量表达式不允许的行为。
内容的提问来源于stack exchange,提问作者ValeriyKarasikov

