Home > other >  Understanding concepts. Check if a member is static
Understanding concepts. Check if a member is static

Time:12-05

Lets say we have a simple concept like:

template <typename T>
concept MyConcept = requires {
    T::value == 42; 
};

In my understanding the concept says that, if the code T::value == 42 is valid for the type T, I pass. So the value MUST be a static member, right?

I have a struct

struct Test { int value = 0; }

and the next template function

template <MyConcept T>
void call() { /*...*/ }

and when I try to do this:

int main()
{
    call<Test>();
}

It works!

And the question is: why does it work? Test::value == 42 is not a valid code for the type Test.

I found a method to fix it like:

template <typename T>
concept MyConcept = requires {
    *(&T::value) == 42; 
};

And it "works" as expected:

<source>:6:20: note: the required expression '((* & T::value) == 42)' is invalid

And this concept works for the static value only, as it should be. But why does the T::value == 42 work?

godbolt: https://godbolt.org/z/d3GPETEq9

UPD: example https://godbolt.org/z/d8qfzK9b6

CodePudding user response:

And this concept works for the static value only, as it should be. But why does the T::value == 42 work?

Because there's actually an exception in the rule you think will cause this to fail.

The rule, from [expr.prim.id.general]/3 is, emphasis mine:

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 class51 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 3:

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

end example]

That third bullet right there: T::value is usable as an unevaluated operand. All the expressions you check in a requirement are unevaluated. So T::value works for non-static data members just fine.

  • Related