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?
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.