Use-cases for Concepts
Discover use-cases of concepts in C++20.
We'll cover the following...
First and foremost, concepts are compile-time predicates. A compile-time predicate is a function that is executed at compile-time and returns a boolean.
Before I dive into the various use-cases of concepts, I want to demystify concepts and present them simply as functions returning a boolean at compile time.
Compile-time predicates
A concept can be used in a control structure, which is executed at run time or compile-time. Run the code below.
In the program above, I use the concept std::three_way_comparableT supports the six comparison operators. Being a compile-time predicate means that std::three_way_comparable can be used at run time (lines 14 and 18) or at compile time. static_assert (line 23) and if constexpr (lines 26 and 32) are evaluated at compile time.
Class templates
The class template MyVector requires that its template parameter T be regular, meaning that T behaves such as an int. The formal definition of regular is provided later in this chapter.
Warning: The code gives an error message.
Line 9 causes a compile-time error because a reference is not regular.
Generic member functions
In the code below, I add a generic push_back member function to the class MyVector. push_back requires that its arguments be copyable.
Warning: The code gives an error message.
The compilation fails intentionally at line 18. Instances of NotCopyable are not copyable because the copy constructor is declared as deleted.
Variadic templates
You can use concepts in variadic templates.
The definitions of the function templates above are based on fold expressions. C++11 supports variadic templates that can accept an arbitrary number of template arguments. The arbitrary number of template parameters is held by a so-called parameter pack. Additionally, with C++17 you can directly reduce a parameter pack with a binary operator. This reduction is called a fold expression.
In this example, the && (line 6), (||) (line 11), and the negation of the logical or (line 16) are applied as binary operators. Furthermore, all, any, and none require from its type parameters that they have to support the concept std::integral.