The Template Introduction from the Concepts TS is a new way to use concepts. This syntactic variant is not included in the Concepts Draft and, therefore, in the C++20 standard. But, I don't know what the farther away future brings.

Template Introduction
Let me first start with a short riddle. Which one, of the following syntactic variants, is not possible with the draft of the concept?
template<typename T> // (1)
requires Integral<T>
T gcd(T a, T b){
if( b == 0 ) return a;
else return gcd(b, a % b);
}
template<typename T> // (2)
T gcd1(T a, T b) requires Integral<T>{
if( b == 0 ){ return a; }
else return gcd(b, a % b);
}
template<Integral T> // (3)
T gcd2(T a, T b){
if( b == 0 ){ return a; }
else return gcd(b, a % b);
}
Integral auto gcd3(Integral auto a, Integral auto b){ // (4)
if( b == 0 ){ return a; }
else return gcd(b, a % b);
}
Integral{T} // (5)
Integral gcd(T a, T b){
if( b == 0 ){ return a; }
else{
return gcd(b, a % b);
}
}
Maybe, you don't know. So let me name the five variants.
- Requires clause
- Trailing requires clause
- Constrained template parameters
- Abbreviated Function Templates
- Template Introduction
I assume you have chosen the most obscure one: Template Introduction. You are right. Maybe we get it with a later C++ standard, but I'm highly sceptical. In my talks in the last year, I heard no one complaining that they are not part of C++20. I'm also not a big fan of Template Introduction because they introduced a new asymmetry, and you know, I'm not a fan of asymmetries.
The Asymmetry
Instead of declaring your constrained template by using template<Integral T>, you can just Integral{T}. Here, you see the asymmetry. You can only use Template Introduction with concepts (constrained placeholders) but not with auto (unconstrained placeholders). The following example makes my point. This and the following example is based on the previous concepts TS specification and compiled with the GCC.
// templateIntroduction.cpp
#include <type_traits>
#include <iostream>
template<typename T>
concept bool Integral(){
return std::is_integral<T>::value;
}
Integral{T} // (1)
Integral gcd(T a, T b){
if( b == 0 ){ return a; }
else{
return gcd(b, a % b);
}
}
Integral{T} // (2)
class ConstrainedClass{};
/*
auto{T} // (4)
auto gcd(T a, T b){
if( b == 0 ){ return a; }
else{
return gcd(b, a % b);
}
}
auto{T} // (5)
class ConstrainedClass{};
*/
int main(){
std::cout << std::endl;
auto res= gcd(100, 10);
ConstrainedClass<int> constrainedClass;
ConstrainedClass<double> constrainedClass1; // (3)
std::cout << std::endl;
}
I use Template introduction for the function template gcd (line 1) and the class template ConstrainedClass (line 2). As expected, the concept will kick in if I try to instantiate ConstraintedClass for double (line 3).

I don't like it that I can not just replace Integral with auto such as in lines 4 and 5. Up to this point in my posts to concepts, I used constrained placeholders (concepts) and unconstrained placeholders (auto) interchangeably. This straightforward principle is gone with Template Introduction.
Of course, I could easily overcome this restriction by defining a concept that always evaluated to true.
// templateIntroductionGeneric.cpp
#include <iostream>
#include <string>
#include <typeinfo>
#include <utility>
struct NoDefaultConstructor{ // (5)
NoDefaultConstructor() = delete;
};
template<typename T> // (1)
concept bool Generic(){
return true;
}
Generic{T} // (2)
Generic gcd(T a, T b){
if( b == 0 ){ return a; }
else{
return gcd(b, a % b);
}
}
Generic{T} // (3)
class ConstrainedClass{
public:
ConstrainedClass(){
std::cout << typeid(decltype(std::declval<T>())).name() // (4)
<< std::endl;
}
};
int main(){
std::cout << std::endl;
std::cout << "gcd(100, 10): " << gcd(100, 10) << std::endl;
std::cout << std::endl;
ConstrainedClass<int> genericClassInt;
ConstrainedClass<std::string> genericClassString;
ConstrainedClass<double> genericClassDouble;
ConstrainedClass<NoDefaultConstructor> genericNoDefaultConstructor;
std::cout << std::endl;
}
Generic (line 1) is a concept that returns true for all types. Now, I can unify the syntax and define an unconstrained function template (line 4) and an unconstrained class template (line 3). Honestly, the terms unconstrained or constrained function templates or class template are not official. I coined them for simplicity reasons.
The expression typeid(decltype(std::declval<T>())).name() (line 4) may look weird to you. std::declvar<T> (C++11) converts the type parameter T into a reference type. Thanks to the reference type, you can use it in a decltype expression to invoke any member function on T without constructing T. It works even for a type T without a default constructor (line 5). In my case (line 4), I invoked the constructor on the reference type to get the string representation of the type parameter T. Here is the output of the program with GCC.

What's next?
One big topic is left to complete the story to concepts: define your concept. Most of the times, you reinvent the wheel because C++20 has many pre-defined concepts. Anyway, I present with my next post the pre-defined concepts and who you can define your own.
This is my last post for 2019. You hear from me on 12.01.2020. If your hopefully contemplative time is too contemplative, here are about 300 posts to modern C++: |
 |
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: |
|
 |
Get your e-book 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. 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
|
 |
 |
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
|
Read more...