Search code examples
c++language-lawyerc++20c++23consteval

consteval member function allowed?


I have this c++20/23 code:

#include <cstddef>

template <size_t N>
class Foo {
    public:
        consteval size_t size() noexcept { return N; }

        size_t real_size() {
            return size() - 1;
        }
};

int main(int argc, char* argv[]) {
    Foo<5> foo;
    return foo.real_size();
}

clang 10 and gcc 14.1 can compile it without any error/warning.

However, clang 14-18.1 emits error:

<source>:9:20: error: call to consteval function 'Foo<5>::size' is not a constant expression
    9 |             return size() - 1;
      |                    ^
<source>:15:16: note: in instantiation of member function 'Foo<5>::real_size' requested here
   15 |     return foo.real_size();
      |                ^
<source>:9:20: note: implicit use of 'this' pointer is only allowed within the evaluation of a call to a 'constexpr' member function
    9 |             return size() - 1;
      |                    ^
1 error generated.

Which compilers are right per C++20 and C++23 standards? Why?


Solution

  • This is another example of P2280 which clang doesn't implement yet.

    The original C++20 requirement for core constant expressions was that you weren't allowed to evaluate (from C++20's [expr.const]):

    this, except in a constexpr function or a constexpr constructor that is being evaluated as part of e;

    Which got changed to (C++23's [expr.const]):

    this ([expr.prim.this]), except

    • in a constexpr function ([dcl.constexpr]) that is being evaluated as part of E or
    • when appearing as the postfix-expression of an implicit or explicit class member access expression ([expr.ref]);

    The call size() (which is implicitly this->size() because it's a non-static member function) has to be a constant expression (because it's consteval). This original rule rejected evaluating this, but the new one no longer does. So the expression this->size() satisfies the rules of a core constant expression.