C++20: Concepts, the Details

In my last post C++20: Two Extremes and the Rescue with Concepts, I gave the first motivation for concepts. Concepts put semantic constraints on template parameters. Today, I present different use-cases for concepts in a compact form.


The Details

Just do keep it in mind: What are the advantages of concepts?

  • Requirements for templates are part of the interface.
  • The overloading of functions or specialisation of class templates can be based on concepts.
  • We get improved error message because the compiler compares the requirements of the template parameter with the actual template arguments
  • You can use predefined concepts or define your own.
  • The usage of auto and concepts is unified. Instead of auto, you can use a concept.
  • If a function declaration uses a concept, it automatically becomes a function template. Writing function templates is, therefore, as easy as writing a function.

This post is about the first three points. Let me show many different usages of concepts:

Three Ways

There are three ways to use the concept Sortable. For simplicity reasons, I only show the declaration of the function template.

Requires Clause

template<typename Cont>
    requires Sortable<Cont>
void sort(Cont& container);

Trailing Requires Clause

template<typename Cont>
void sort(Cont& container) requires Sortable<Cont>;

Constrained Template Parameters

template<Sortable Cont>
void sort(Cont& container)


The algorithm sort requires in this case that the container is sortable. Sortable has to be a constant expression and a predicate.


You can define a class template which only accepts objects.

template<Object T>
class MyVector{};

MyVector<int> v1;   // OK
MyVector<int&> v2;  // ERROR: int& does not satisfy the constraint Object


The compiler complains that and reference is not an object. Maybe you wonder, what an object is.? A possible implementation der type-traits function std::is_object gives the answer:

template< class T>
struct is_object : std::integral_constant<bool,
                     std::is_scalar<T>::value ||
                     std::is_array<T>::value  ||
                     std::is_union<T>::value  ||
                     std::is_class<T>::value> {};


An object is either a scalar, or an array, or a union, or a class.

Member Functions

template<Object T>
class MyVector{
    void push_back(const T& e) requires Copyable<T>{}


In this case, the member function requires that the template parameter T must be copyable.

Variadic Templates

 // allAnyNone.cpp

#include <iostream>
#include <type_traits> template<typename T> concept Arithmetic = std::is_arithmetic<T>::value; template<Arithmetic... Args> bool all(Args... args) { return (... && args); } template<Arithmetic... Args> bool any(Args... args) { return (... || args); } template<Arithmetic... Args> bool none(Args... args) { return !(... || args); } int main(){ std::cout << std::boolalpha << std::endl; std::cout << "all(5, true, 5.5, false): " << all(5, true, 5.5, false) << std::endl; std::cout << "any(5, true, 5.5, false): " << any(5, true, 5.5, false) << std::endl; std::cout << "none(5, true, 5.5, false): " << none(5, true, 5.5, false) << std::endl; }


You can use concepts in variadic templates.  The definition of the function templates are based on fold expressions. all, any, and none requires from it type parameter T that is has to support the concept Arithmetic. Arithmetic essential means that T is either integral or floating-point.

The brand-new Microsoft compiler 19.23 supports partially as the only one the proposed concepts syntax.


More Requirements

Of course, you can use more than one requirement for the template parameters.

template <SequenceContainer S,   
          EqualityComparable<value_type<S>> T>
Iterator_type<S> find(S&& seq, const T& val){

The function template find requires that the container S is a SequenceContainer and that its elements are EqualityComparable.


std::advance(iter, n) puts its iterator iter n position further. Depending on the iterator, the implementation can use pointer arithmetic or just go n times further. In the first case, the execution time is constant; in the second case, the execution time depends on the stepsize n. Thanks to concepts, you can overload std::advance on the iterator category.

template<InputIterator I>
void advance(I& iter, int n){...}

template<BidirectionalIterator I>
void advance(I& iter, int n){...}

template<RandomAccessIterator I>
void advance(I& iter, int n){...}

// usage

std::vector<int> vec{1, 2, 3, 4, 5, 6, 7, 8, 9};
auto vecIt = vec.begin();
std::advance(vecIt, 5);       //  RandomAccessIterator

std::list<int> lst{1, 2, 3, 4, 5, 6, 7, 8, 9};
auto lstIt = lst.begin();
std::advance(lstIt, 5);       //  BidirectionalIterator

std::forward_list<int> forw{1, 2, 3, 4, 5, 6, 7, 8, 9};
auto forwIt = forw.begin();
std::advance(forwIt, 5);      //  InputIterator

Based on the iterator category, the containers std::vector, std::list, and std::forward_list support, the best fitting std::advance implementation is used.


Concepts also support template specialisations.

template<typename T>
class MyVector{};

template<Object T>
class MyVector{};

MyVector<int> v1;     // Object T
MyVector<int&> v2;    // typename T

  • MyVector<int&> goes to the unconstrained template parameter.

  • MyVector<int> goes to the constrained template parameter.

What's next?

My next post is about the syntactical unification in C++20. With C++20, you can use a constrained placeholder (concept) in each place you could use an unconstrained placeholder (auto) in C++11. But this is not the end of the unification. Defining a template becomes with C++20 a piece of cake. Just use a constrained or an unconstrained placeholder in the declaration of a function.

Thanks a lot to my Patreon Supporters: Paul Baxter,  Meeting C++, Matt Braun, Roman Postanciuc, Venkata Ramesh Gudpati, Tobias Zindl, Marko, G Prvulovic, Reiner Eiteljörge, Reinhold Dröge, Abernitzke, Richard Ohnemus, Frank Grimm, Sakib, Broeserl, António Pina, Markus Falkner, Darshan Mody, Sergey Agafyin, Андрей Бурмистров, and Jake.


Thanks in particular to:   crp4



Get your e-book at Leanpub:

The C++ Standard Library


Concurrency With Modern C++


Get Both as one Bundle

cover   ConcurrencyCoverFrame   bundle
With C++11, C++14, and C++17 we got a lot of new C++ libraries. In addition, the existing ones are greatly improved. The key idea of my book is to give you the necessary information to the current C++ libraries in about 200 pages. I also included more than 120 source files.  

C++11 is the first C++ standard that deals with concurrency. The story goes on with C++17 and will continue with C++20.

I'll give you a detailed insight in the current and the upcoming concurrency in C++. This insight includes the theory and a lot of practice with more than 140 source files.


Get my books "The C++ Standard Library" (including C++17) and "Concurrency with Modern C++" in a bundle.

In sum, you get more than 700 pages full of modern C++ and more than 260 source files presenting concurrency in practice.


Get your interactive course


Modern C++ Concurrency in Practice

C++ Standard Library including C++14 & C++17

educative CLibrary

Based on my book "Concurrency with Modern C++" educative.io created an interactive course.

What's Inside?

  • 140 lessons
  • 110 code playgrounds => Runs in the browser
  • 78 code snippets
  • 55 illustrations

Based on my book "The C++ Standard Library" educative.io created an interactive course.

What's Inside?

  • 149 lessons
  • 111 code playgrounds => Runs in the browser
  • 164 code snippets
  • 25 illustrations

Add comment

My Newest E-Books

Course: Modern C++ Concurrency in Practice

Course: C++ Standard Library including C++14 & C++17

Course: Embedded Programming with Modern C++

Course: Generic Programming (Templates)

Subscribe to the newsletter (+ pdf bundle)

Blog archive

Source Code


Today 1572

All 2994325

Currently are 202 guests and no members online

Kubik-Rubik Joomla! Extensions

Latest comments