What is Concept?

If we have a Template class defining templated or non templated functions.
When call to functions inside this class is made, template class can select most appropriate(Based on template arguments) function from overloaded funtions or template specialization from specializations.
Concepts allow to provide constraints on templates and have the compiler enforce them. Named sets of such requirements are called concepts, Concepts is a Predicate means evaluated at compile time

Example

1. Created a concept named 'TEST'. Any type of <typename T> should satify these conditions:
  hash{}(a) compiles and its result is convertible to std::size_t

2. Create a function whose arguments should adhere to concept TEST.
  Hash of String "abc" can be calculated and be converted to size_t.
  Hash of structure cannot be calculated.

template <typename T>
concept TEST = requires(T a) {                  //1
    { std::hash <T>{}(a) } -> std::convertible_to;    //1
};
    
template <TEST K>                    //2
void f(K){ std::cout << "fun"; }
    
int main() {
    f("abc"s);                        //2a
    struct st{};
    f(st);                            //2b  Error: st does not satisfy TEST
}
                

Contraint

Defines the requirement on template argument used in concept. This is a sequence of logical operations and operands.
They can appear within requires-expressions (see below) and directly as bodies of concepts.

Types of Contraints

Type Description Code
1. Conjunctions The conjunction of two constraints is formed by using the && operator in the constraint expression

template <class T>
concept SignedIntegral = Integral && std::is_signed::value;
                
2. Disjunctions The disjunction of two constraints is formed by using the || operator in the constraint expression.

template <class T = void>
    requires EqualityComparable || Same
struct equal_to;
                
3. Atomic Constraints