struct A {
int i;
consteval A() { i = 2; };
consteval void f() { i = 3; }
};
constexpr bool g() {
A a;
a.f();
return true;
}
int main() {
static_assert(g());
}
https://godbolt.org/z/hafcab7Ga
该程序被所有 GCC、Clang、MSVC 和 ICC 拒绝,并被替换为所有四个都接受它的constexpr
结果。g
consteval
但是,当删除呼叫时a.f();
,仍然使用constexpr
on g
,只有 ICC 仍然拒绝代码。其他三个现在接受它。
我不明白为什么会这样。我的理解是,没有consteval
on g
,表达式a.f()
不在直接函数上下文中,这将导致成员函数调用本身被评估为单独的常量表达式,然后无法修改i
成员,因为成员的生命周期在评估期间没有开始那个不变的表达。
但是为什么构造函数可以在同一个上下文中对同一个对象执行相同的操作呢?的生命周期是否a
被认为是在评估 consteval 构造函数期间开始的?
另请注意, 的存在static_assert
不会影响这些结果。constexpr
从那时起完全删除g
也不会改变编译器行为的任何内容。
正如@Enlico 所指出的,即使在除接受代码的ICC 之外的所有编译器中都替换A a;
和a.f();
替换A{}.f();
为constexpr
ong
结果,尽管据我了解,此表达式应导致对立即构造函数调用和立即成员函数的两个单独的常量表达式进行评估调用。我认为后一个调用的行为应该与 完全相同a.f();
,这使得这更加混乱。
(阅读@Barry 的回答后,我现在意识到最后一句话没有任何意义。更正:A{}
将是构造函数立即调用的一个常量表达式,并且A{}.f()
作为一个整体将是成员函数立即调用的第二个常量表达式。这显然与表达式不同a.f()
。)