Why do we use Concept&Constraint
The purpose of constraints is to allow you to specify pre-conditions on operations using built-in language constructs. Those pre-conditions could be checked by the compiler and either:
- You'll get a clear error message.
- The overload will not be considered in overload resolution (yes, one more way to do SFINAE).
The error messages are nice to have, but the new pre-condition checks for #2 are the real meat of this. What you'd need to do before C++20 to obtain the same effect is something like this:
template<typename T,
std::enable_if_t<has_less_than_op<T>::value, int> = 0>
const T& comp(const T& a , const T& b)
{return a<b?a:b;}
It's clunky and cumbersome, and you need to have foreknowledge about SFINAE techniques to understand why someone would ever write something like that. It's extremely expert friendly. Templates already have that power, but that is an historical coincidence. Concepts (lite) and constraints give the ability to express the same thing in a much more natural way.
Compare the above with your OP or this:
template<LessCompareable T>
const T& comp(const T& a , const T& b)
{return a<b?a:b;}
Which of the alternatives expresses things clearer? Not the old technique, I'd say.