I think the core issue here is that WG21 seems hell bent on refusing any new syntax if at all possible, and instead requires "generic" solutions that can be used for many problems. The result of which is these unending train wreck solutions for what should be basic, and we end up with enable_if and SFINAE. At least C++ finally has the idea of specifying an interface for a template instantiation, except of course it's absurd in its own way. Rather than specifying an API, you write "code" and a type conforms to that concept if the code "compiles". So you have no way to say "I expect this type to conform to this concept" other than using it.
The primary goal of "concepts" appears to be to mitigate the awful error messages, but even for that it fails.
For example, let's imagine Hashable from any other language, and look at a C++ concept version:
template <typename T>
concept Equatable = requires (const T& a, const T& b) {
{ a == b } -> std::same_as<bool>;
};
template <typename T>
concept Hashable = Equatable<T> && requires (const T& a) {
{ a.hashCode() }->std::convertible_to<size_t>;
};
and an implementation:
struct Thing {
size_t hashCode() const;
};
bool operator==(Thing, Thing);
Now how do we make sure Thing is actually going to conform to Hashable? with an assert of course, why would we want anything so gauche as declarative syntax?
static_assert(Hashable<Thing>);
You can see the brilliant syntax explicitly disallows us specifying constraints on a concept, and instead we have to use the && expression. My personal belief here is that the banning of constraints in the template name is simply to force people to use logical composition so the people who thought of it can claim people like it.