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
The program is rejected by all of GCC, Clang, MSVC and ICC and replacing constexpr
on g
by consteval
results in all four accepting it.
However, when removing the call a.f();
, still with constexpr
on g
, only ICC still rejects the code. The other three now accept it.
I don't understand why this is the case. My understanding is that without consteval
on g
, the expression a.f()
is not in an immediate function context, which will cause the member function call itself to be evaluated as separate constant expression, which then cannot modify the i
member because the member's lifetime didn't begin during evaluation of that constant expression.
But why can the constructor perform the same operation on the same object, in the same context? Is a
's lifetime considered to have begun during the evaluation of the consteval constructor?
Also note that the presence of the static_assert
doesn't affect these results. Removing in addition constexpr
completely from g
then also doesn't change anything about the compiler behavior.
As noted by @Enlico, even replacing both A a;
and a.f();
by A{}.f();
with constexpr
on g
results in all compilers except ICC accepting the code, although by my understanding, this expression should result in evaluation of two separate constant expressions for the immediate constructor invocation and for the immediate member function invocation. I think the latter call should behave exactly as a.f();
, making this even more confusing.
(After reading @Barry's answer, I realize now that the last sentence didn't make any sense. Correction: A{}
would be one constant expression for the constructor immediate invocation and A{}.f()
as a whole would be the second constant expression for the member function immediate invocation. This is clearly different from the expression a.f()
.)
a.f();
toA{}.f();
, you'll also see only ICC errors. Maybe you want to add this info too, to the question. – GermanizeA{}.f()
. – GinnieA{}
would be a subexpression of the function call inA{}.f()
. – Sublime