Constraints, requires-clause:s and requires-expression:s
You need to differentiate between a requires-clause and a requires-expression.
template<Bla b>
void f() requires .... {}
// ^^^^ - constant-expression OR
// requires-expression
//
// ^^^^^^^^^^^^^ - requires-clause
Particularly, as per [temp.pre]/1, the grammar for a requires-clause is:
requires-clause:
requires constraint-logical-or-expression
where constraint-logical-or-expression, in turn, is a primary-expression, which includes requires-expression:s.
Applied to OP:s example: constraining a non-type template parameter
In your case, you are using an ad-hoc requires-expression (as compared to a named constraint) as the requirement for a requires-clause. However, for your use case it suffices to use a requires-clause with a constant-expression. Particularly, you can restrain the value of a non-type template parameter by a constant expression in the trailing requires-clause of a given templated entity, say a function template:
enum class MyEnum {
Foo,
Bar,
Baz
};
// Allows any specialization over MyEnum.
template<MyEnum e>
struct Wrapped {};
// Allows only Wrapped objects of certain
// specializations.
template<MyEnum e>
void f(Wrapped<e>) requires (e == MyEnum::Foo || e == MyEnum::Bar) {
}
int main() {
f(Wrapped<MyEnum::Foo>{}); // OK
f(Wrapped<MyEnum::Bar>{}); // OK
f(Wrapped<MyEnum::Baz>{}); // Error: ... constraints not satisfied
}
Applied for overloading with mutually exclusive constraints:
// Allows any specialization over MyEnum.
template<MyEnum e>
struct Wrapped {};
// Overloading Wrapped specializations by
// mutually exclusive constraints:
template<MyEnum e>
void f(Wrapped<e>) requires (e == MyEnum::Foo || e == MyEnum::Bar) {
std::cout<< __PRETTY_FUNCTION__ << "\n";
}
template<MyEnum e>
void f(Wrapped<e>) requires (e == MyEnum::Baz) {
std::cout<< __PRETTY_FUNCTION__ << "\n";
}
int main() {
f(Wrapped<MyEnum::Foo>{}); // void f(Wrapped<e>) requires e == MyEnum::Foo || e == MyEnum::Bar [with MyEnum e = MyEnum::Foo]
f(Wrapped<MyEnum::Bar>{}); // void f(Wrapped<e>) requires e == MyEnum::Foo || e == MyEnum::Bar [with MyEnum e = MyEnum::Bar]
f(Wrapped<MyEnum::Baz>{}); // void f(Wrapped<e>) requires e == MyEnum::Baz [with MyEnum e = MyEnum::Baz]
}