Home > Net >  How to make `this` pointer constant expression?
How to make `this` pointer constant expression?

Time:09-13

This is a follow-up question is my previous question: Why are member functions returning non-static data members not core constant expressions?

The reduced version of the example mentioned in that question is:

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;
}

The applicable wording from the standard is N4861: [expr.const]/(5.1):

An expression E is a core constant expression unless the evaluation of E, following the rules of the abstract machine ([intro.execution]), would evaluate one of the following:

  • (5.1) this ([expr.prim.this]), except in a constexpr function ([dcl.constexpr]) that is being evaluated as part of E;

As far as I can parse, the expression E is s.f() and it evaluates this since s.f() returns a non-static member this->x. But that falls under the "except" part: the member function s.S::f() is constexpr function that's being evaluated as part of s.f(). If I parsed correctly, I'm expecting s.f() to be constant expression and the assertion success.

However, this bullet doesn't specify a requirement that says that s has to be a constant expression. I can't understand why declaring s as constexpr compiles the program even though there's no requirement, defined in this bullet, for s to be constexpr.

I'm just applying the wording (5.1) in my example but I can't see that constexpr is required here unless I'm missing any other rule.

CodePudding user response:

Because return x; performs lvalue-to-rvalue conversion, the whole kaboodle is not a core constant expression:

An expression E is a core constant expression unless the evaluation of E, following the rules of the abstract machine ([intro.execution]), would evaluate one of the following:

lvalue-to-rvalue conversion is applied to this->S::x, which is generally forbidden, and neither of the exceptions apply to permit it.

The more relevant exception applies if x (which resolves to this->S::x) is an object that is usable in constant expressions. But it only would be if the struct S object were usable in constant expressions:

That requires it to be potentially-constant:

And S s{}; is not potentially-constant. So it is not usable in constant expressions, and neither are its subobjects.

  • Related