mad*_*ada 0 c++ this language-lawyer constant-expression
这是我之前的问题的后续问题:为什么成员函数返回非静态数据成员而不是核心常量表达式?
该问题中提到的示例的简化版本是:
struct S {
const bool x = true;
constexpr bool f() { return x; }
};
int main() {
S s{};
static_assert(s.f()); // error: 's' is not a constexpr;
}
Run Code Online (Sandbox Code Playgroud)
标准中适用的措辞是 N4861:[expr.const]/(5.1):
表达式
E是核心常量表达式E,除非 的计算遵循抽象机 ([intro.execution]) 的规则,将计算以下其中一项:
- (5.1) ([expr.prim.this]),但作为 的一部分进行求值的函数 ([dcl.constexpr])
this除外;constexprE
据我可以解析,表达式E是并且s.f()它的计算结果是返回一个非静态成员。但这属于“例外”部分:成员函数是 constexpr 函数,它作为. 如果我解析正确,我期望得到常量表达式并且断言成功。thiss.f()this->xs.S::f()s.f()s.f()
s但是,该项目符号并未指定必须是常量表达式的要求。我不明白为什么声明sasconstexpr会编译程序,即使没有在此项目符号中定义的s要求constexpr。
我只是在我的示例中应用了措辞(5.1),但我看不到constexpr这里需要这样做,除非我错过了任何其他规则。
因为return x;执行左值到右值的转换,所以整个kaboodle不是核心常量表达式:
表达式 E 是核心常量表达式,除非对 E 的求值遵循抽象机 ([intro.execution]) 的规则,将求值以下其中一项:
引用可在常量表达式中使用的对象的非易失性泛左值,或者
文字类型的非易失性泛左值,指的是其生命周期开始于 E 求值期间的非易失性对象;
左值到右值的转换应用于,this->S::x这通常是被禁止的,并且两个例外都不允许这样做。
x如果(解析为this->S::x)是可在常量表达式中使用的对象,则应用更相关的异常。但只有当该struct S对象可在常量表达式中使用时才会出现这种情况:
这要求它是潜在恒定的:
并且S s{};不是潜在恒定的。所以它不能用在常量表达式中,它的子对象也不能用。
回答标题问题,this不是核心常量表达式,因为它是一个具有自动存储期限的对象的地址;该地址可能会在运行时更改。这与static_assert问题代码中的完全无关:作为常量指针值对于this指针“可在常量表达式中使用”来说既不是必要的也不是充分的,这反过来又不足以使通过指针找到的对象可在常量表达式。