We will get concepts with high probability in C++20. Here are from the C++ core guidelines the rules to use them.
First, let me go one step back. What are concepts?
 Concepts are a compiletime predicate. This means concepts can be evaluated at compiletime and return a boolean.
The next questions are. What are the pros of concepts in C++?
Concepts
 Empower programmer to directly express their requirements as part of the interface.
 Support the overloading of functions and the specialisation of class templates based on the requirements of the template parameters.
 Produce drastically improved error messages by comparing the requirements of the template parameter with the applied template arguments.
 Can be used as placeholders for generic programming.
 Empower you to define your concepts.
Now, one step forward. Here are the four rules for today:
Let's start with the first rule.
There is not much to add to this rule. Because of correctness and readability, you should use concepts for all template parameters. You can do it in a verbose way.
template<typename T>
requires Integral<T>()
T gcd(T a, T b){
if( b == 0 ){ return a; }
else{
return gcd(b, a % b);
}
}
Or you can do it more concise.
template<Integral T>
T gcd(T a, T b){
if( b == 0 ){ return a; }
else{
return gcd(b, a % b);
}
}
In the first example, I specify the concept in the require clause, but I can use the concept Integral
just in place of the keyword typename or class. The concept Integral
has to be a constant expression that returns a boolean.
I created the concept by using std::is_integral
from the type traits library.
template<typename T>
concept bool Integral(){
return std::is_integral<T>::value;
}
Defining your concepts such as I did it, is not the best idea.
Okay, if possible you should use the concepts from the Guidelines Support Library (GSL) or the Ranges TS. Let's see what we have. I ignore the concepts of the GSL because they are mainly part of the Ranges TS. Here are the concepts of the Range TS from the document N4569: Working Draft, C++ Extension for Ranges.
Core language concepts
Same
DerivedFrom
ConvertibleTo
Common
Integral
Signed Integral
Unsigned Integral
Assignable
Swappable
Comparison concepts
Boolean
EqualityComparable
StrictTotallyOrdered
Object concepts
Destructible
Constructible
DefaultConstructible
MoveConstructible
Copy Constructible
Movable
Copyable
Semiregular
Regular
Callable concepts
Callable
RegularCallable
Predicate
Relation
StrictWeakOrder
If you want to know, what each of this concepts means, the already mentioned document N4569 gives you the answers. The concept definitions are based on the type traits library. Here are for example the definitions of the concepts Integral, Signed Integral
, and Unsigned Integral
.
template <class T>
concept bool Integral() {
return is_integral<T>::value;
}
template <class T>
concept bool SignedIntegral() {
return Integral<T>() && is_signed<T>::value;
}
template <class T>
concept bool UnsignedIntegral() {
return Integral<T>() && !SignedIntegral<T>();
}
The functions std::is_integral<T>
and std::is_signed<T>
are predicates from the type traits library.
Additionally, there are the names used in the text of the C++ standard to define the expectations of the standard library. They are concepts which are not enforced but document the requirement for an algorithm such as std::sort
.
template< class RandomIt >
void sort( RandomIt first, RandomIt last );
The first overload of std::sort
requires two RandomAccessIterator's. Now, I have to say what a RandomAccessIterator is:
 A RandomAccessIterator is a BidirectionalIterator that can be moved to point to any element in constant time.
 A BidirectionalIterator is a ForwardIterator that can be moved in both directions
 A ForwardIterator is an Iterator that can read data from the pointedto element.
 The Iterator requirements describe types that can be used to identify and traverse the elements of a container.
For the details to the named requirements used in the text of the C++ standard, read cppreference.com.
auto
is an unconstrained concept (placeholder) but you should use constrained concepts. You can use constrained concepts in each situation where you can use unconstrained placeholders (auto). If this is not an intuitive rule?
Here is an example to make my point.
// constrainedUnconstrainedConcepts.cpp
#include <iostream>
#include <type_traits>
#include <vector>
template<typename T> // (1)
concept bool Integral(){
return std::is_integral<T>::value;
}
int getIntegral(int val){
return val * 5;
}
int main(){
std::cout << std::boolalpha << std::endl;
std::vector<int> myVec{1, 2, 3, 4, 5};
for (Integral& i: myVec) std::cout << i << " "; // (2)
std::cout << std::endl;
Integral b= true; // (3)
std::cout << b << std::endl;
Integral integ= getIntegral(10); // (4)
std::cout << integ << std::endl;
auto integ1= getIntegral(10); // (5)
std::cout << integ1 << std::endl;
std::cout << std::endl;
}
I defined the concept Integral
in line (1). Hence I iterate over integrals in the rangebased forloop in line (2) and the variables b
and integ
in line (3) and (4) has to be integrals. I'm not so strict in line (5). Here I'm fine with an unconstrained concept.
In the end, the output of the program.
The example from the C++ Core Guidelines looks quite innocent but has the potential to revolutionise the way we write templates. Here it is.
template<typename T> // Correct but verbose: "The parameter is
// requires Sortable<T> // of type T which is the name of a type
void sort(T&); // that is Sortable"
template<Sortable T> // Better (assuming support for concepts): "The parameter is of type T
void sort(T&); // which is Sortable"
void sort(Sortable&); // Best (assuming support for concepts): "The parameter is Sortable"
This example shows three variations to declare the function template sort
. All variations are semantically equivalent and require that the template parameter supports the concept Sortable
. The last variation looks like a function declaration but is a function template declaration because the parameter is a concept and not a concrete type. To say it once more: sort
becomes due to the concept parameter a function template.
What's next?
The C++ core guidelines say: "Defining good concepts is nontrivial. Concepts are meant to represent fundamental concepts in an application domain." Let's see what that mean in my next post.
Thanks a lot to my Patreon Supporters: Eric Pederson, Paul Baxter, Meeting C++, Matt Braun, Avi Lachmish, Roman Postanciuc, Venkata Ramesh Gudpati, Tobias Zindl, Mielo, and Dilettant.
Thanks in particular to:
Get your ebook at Leanpub:
The C++ Standard Library


Concurrency With Modern C++


Get Both as one 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. 

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 the 100 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 600 pages full of modern C++ and more than 100 source files presenting concurrency in practice.

Get your interactive course at educative

Modern C++ Concurrency in Practice: Get the most out of any machine


Based on my book "Concurrency with Modern C++" educative.io created an interactive course.
What's Inside?
 140 lessons
 110 code playgrounds => Run in browser
 78 code snippets
 55 illustrations

Read more...