I can't find the correct syntax on cppreference for a concept that matches the value of a static constexpr
member. This code compiles, and functions correctly on GCC and MSVC, but does not work in Clang. I was wondering if anybody knew if this was my mistake, or an issue with either GCC and MSVC or Clang?
Here's a godbolt with all three compilers open, I think it illustrates the point!
#include <concepts>
#include <iostream>
template<typename T>
concept MyConcept = requires (T t){
requires t.member == 1;
//[clang's error]
// note: because 't.member == 1' would be invalid:
// constraint variable 't' cannot be used in an evaluated context
};
struct S {
constexpr static int member {2};
};
struct D {
constexpr static int member {1};
};
template<MyConcept T>
void func(){
std::cout << "matched\n";
}
int main(){
func<D>();
return 0;
}
Clang is correct here (thanks, Casey).
[expr.prim.req.nested]/2 says:
A local parameter shall only appear as an unevaluated operand within the constraint-expression.
And [expr.ref]/1 says:
A postfix expression followed by a dot
.
or an arrow->
, optionally followed by the keyword template, and then followed by an id-expression, is a postfix expression. The postfix expression before the dot or arrow is evaluated;55 the result of that evaluation, together with the id-expression, determines the result of the entire postfix expression.
In t.member
, that evaluates t
, and we're not allowed to do that in this context.
A different way to express this would be to drop the requirement-body entirely and check the static member directly:
template<typename T>
concept MyConcept = T::member == 1;
Concept definitions are arbitrary boolean expressions, so this is sufficient and doesn't run afoul of any rules.