Concepts (C++20)

A mechanism to place constraints on your template type parameters. An alternative to static asserts and type traits. This is a great feature to enforce rules on the users of your templates.


#include <iostream>
#include <type_traits>

template <typename T> void print_number(T n) {
  static_assert(std::is_integral<T>::value, "Must pass an integral argument");
  std::cout << "n : " << n << std::endl;
}

int main() {
  print_number(5);
  // print_number(55.2); will fail to compile
}

In C++, there are standard built in concepts, but we can also create our own ones.

Some built in concepts:

  • same_as
  • derived_from
  • convertible_to
  • common_reference_with
  • common_with
  • integral
  • signed_integral
  • unsigned_integral
  • floating_point

Syntax for using concepts:


#include <concepts>

template <typename T>
  requires std::integral<T>
T add(T a, T b) {
  return a + b;
}

int main() {
  add(4, 8);
  // add(4.5, 8.6); error: constraint not satisfied
}

You can also use type traits:


template <typename T>
  requires std::is_integral_v<T>
T add(T a, T b) {
  return a + b;
}

You can also specify your concept directly:


template <std::integral T> T add(T a, T b) { return a + b; }

Using auto:


auto add(std::integral auto a, std::integral auto b) { return a + b; }

There are many syntax possibilities, some works better depending on the situation.


template <typename T>
T add(T a, T b) requires std::is_integral_v<T> {
  return a + b;
}