"requires" ignores a field is not static

Viewed 128

Consider the following code:

#include <iostream>

constexpr int fun(int const&) { return 5; }
struct T { int x; };

int main() {
  std::cout << fun(T::x) << std::endl;                   // Line A
  std::cout << requires { fun(T::x); } << std::endl;     // Line B
}

If I only comment Line B, then the code cannot be compiled (as expected, since x is not static in T). But when I only comment Line A, the code compiles just fine with both Clang 11.0.0 and GCC 10.2.0 (both output 1). What it is that I am missing about requires? shouldn't it return false?

1 Answers

A requires expression is one big list of unevaluated operands.

[expr.prim.req]

2 A requires-expression is a prvalue of type bool whose value is described below. Expressions appearing within a requirement-body are unevaluated operands.

And a qualified-id naming a non-static data member always could appear in an unevaluated operand.

[expr.prim.id]

2 An id-expression that denotes a non-static data member or non-static member function of a class can only be used:

  • as part of a class member access in which the object expression refers to the member's class or a class derived from that class, or

  • to form a pointer to member ([expr.unary.op]), or

  • if that id-expression denotes a non-static data member and it appears in an unevaluated operand. [ Example:

struct S {
  int m;
};
int i = sizeof(S::m);           // OK
int j = sizeof(S::m + 42);      // OK

— end example ]

The unevaluated operand where T::x may appear can be any expression. So even pre-C++20 you could for example write

decltype(fun(T::x)) i{};
Related