Concepts - Placeholders

Contents[Show]

C++11 has auto unconstrained placeholders. You can use concepts in C++20 as constrained placeholders. What seems at first glimpse not so thrilling is for me the decisive quantum leap. C++ templates will become an easy to use C++ feature.

Before I present the new syntax, I have to make a short remark. After my research to concepts and my experiments with unconstrained and constrained placeholders, I'm very biased. Therefore you can not expect a quite objective post.   

An ever and ever-recurring question

I hear often in my C++ and Python seminars the question: When is a programming language easy? Of course, the answer can not be that a programming language is easy if you can solve difficult questions in an easy way. That is a contradiction.

For me, a programming language is easy if you can reduce it to a few simple principles. I call such a principle a red thread. I hope you get the German proverb. The idea of these few simple principles is that you can deduce the features of the language from these principles. According to my definition, Python is a simple programming language. For example, if you get the idea of building slices on a sequence, you can apply this principle in many contexts.

slice

Therefore, the syntax will follow the same principle if I want to return each third element of a just-in-place created range range(0,10,3), a string,  a list, or a tuple. The same principle will hold if I return the second element of a just-in-place created range range(9,0,-2),  a string, a list or a tuple in reverse order.

According to my definition, C++98 is not a simple language. C++11 is something in between. For example, we have rules such as you can initialize all with curly braces (see { } - Initialization). Of course, even C++14 has a lot of features where I miss a simple principle. One of my favourites is the generalised lambda function.

1
2
3
4
5
6
auto genLambdaFunction= [](auto a, auto b) { return a < b; };

template <typename T, typename T2>
auto genFunction(T a, T2 b){
  return a < b;
}

 

By using the placeholder auto for the parameter a and b the generalised lambda function becomes in a magic way a function template. (I know, genLambdaFunction is a function object that has an overloaded call operator which accepts two type parameters.). genFunction is also a function template but you can not just define it by using auto. Hence you have to use a lot more syntax (line 3 and 4). That is the syntax which is often too difficult for a lot of C++ programmer. 

Exactly that asymmetry will be removed with the placeholder syntax. Therefore, we have a new simple principle and C++ will become - according to my definition - a lot easier to use.

 

Rainer D 6 P2 540x540Modernes C++ Mentoring

Be part of my mentoring programs:

 

 

 

 

Do you want to stay informed about my mentoring programs: Subscribe via E-Mail.

Placeholders

We will get unconstrained and constrained placeholders. auto is an unconstrained placeholder because a auto defined variable can be of any type. A concept is a constrained placeholder because it can only be used to define a variable that satisfies the concept. I introduced concepts in the post Concepts with the help of Haskell's type classes. I got international praise and blame for my approach.

Let me define and use a simple concept before I dig into the details.

A simple concept

Thanks to the concept Integral, the arguments of my gcd algorithm have to be integrals.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// conceptsIntegral.cpp

#include <type_traits>
#include <iostream>

template<typename T>
concept bool Integral(){
  return std::is_integral<T>::value;
}

template<typename T>
requires Integral<T>()
T gcd(T a, T b){
  if( b == 0 ){ return a; }
  else{
    return gcd(b, a % b);
  }
}

int main(){

  std::cout << std::endl;

  std::cout << "gcd(100, 10)= " <<  gcd(100, 10)  << std::endl;
  std::cout << "gcd(100, 33)= " << gcd(100, 33) << std::endl;
  // std::cout << "gcd(5.5, 4,5)= " << gcd(5.5, 4.5) << std::endl;

  std::cout << std::endl;

}

 

I define in line 6 the concept  Integral. The concept Integral will evaluate to true if the predicate std::is_integral<T>::value returns true for T. std::is_integral<T> is a function of the type-traits library. The functions of the type-traits library enable amongst other things that you can check types at compile time. You can read the details about the type-traits in the posts about the type-traits library.  In particular,  I used the functions of the type-traits library to make the gcd algorithm more and more type-safe: More and More Save. I applied the concept in line 12. I will write in my next post how you can apply a concept in a simpler way. Therefore, the border between function templates and function successively distinguish.

But now, back to my small example. Thanks to the relatively new GCC 6.3 and the compiler flag -fconcepts, I can compile and run the program.

conceptsIntegral

What will happen if I use line 26? The concept kicks in.

conceptsIntegralError

Once more, back to the placeholders. To be specific, constrained and unconstrained placeholders.

Constrained and unconstrained placeholders

You can use constrained placeholders (concepts) in each situation where you can use unconstrained placeholders (auto). If this is not an intuitive rule?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// conceptsPlaceholder.cpp

#include <iostream>
#include <type_traits>
#include <vector>

template<typename T>
concept bool Integral(){
  return std::is_integral<T>::value;
}

Integral getIntegral(auto val){
  return val;
}

int main(){
  
  std::cout << std::boolalpha << std::endl;
  
  std::vector<int> myVec{1, 2, 3, 4, 5};
  for (Integral& i: myVec) std::cout << i << " ";
  std::cout << std::endl;  

  Integral b= true;
  std::cout << b << std::endl;
  
  Integral integ= getIntegral(10);
  std::cout << integ << std::endl;
  
  auto integ1= getIntegral(10);
  std::cout << integ1 << std::endl;
  
  std::cout << std::endl;

}

 

For simplicity reasons, I reuse the concept Integral in line 7 - 10. Hence I iterate over integrals in the range-based for-loop in line 21 and my variable b in line 24 has to be integral. My usage of concepts goes on in line 27 and 30. I require in line 27 that the return type of getIntegral(10) has to fulfil the concept Integral.  I'm not so strict in line 30. Here I'm fine with an unconstrained placeholder.

In the end, as ever, the output of the program. There was no surprise. Concepts behave totally intuitive.

conceptsPlaceholder

That's the end of my post. Of course, it's not! I guess most of you didn't recognise that I secretly introduced a new key feature of placeholders. Have a close look at the function getIntegral (line 12).

Integral getIntegral(auto val){
  return val;
}

The concept Integral as the return type is quite easy to get because it's possible to use unconstrained placeholders as return type since C++11. With C++20, we can use - according to the simple rule - constrained placeholders. My point is a different one. I use auto for the type of the parameter. That is only possible for generalised lambda functions (see the first example). A generalised lambda function is under the hood a function template. Now, I will come back to my red thread. getIntegral becomes due to the auto parameter a function template.  That is happening without the usual function template syntax. getIntegral accepts arbitrary types and returns only values of a type that fulfils the concept Integral.

What's next?

In the next post, I will continue my story about placeholders because the unification of templates, concepts, and placeholders goes on.

 

 

Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Animus24, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Kris Kafka, Mario Luoni, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschläger, Alessandro Pezzato, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Leo Goodstadt, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, Michael Young, Holger Detering, Bernd Mühlhaus, Matthieu Bolt, Stephen Kelley, Kyle Dean, Tusar Palauri, Dmitry Farberov, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, Wolfgang Fütterer, Matthias Grün, Phillip Diekmann, Ben Atakora, Ann Shatoff, and Rob North.

 

Thanks, in particular, to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, and Slavko Radman.

 

 

My special thanks to Embarcadero CBUIDER STUDIO FINAL ICONS 1024 Small

 

My special thanks to PVS-Studio PVC Logo

 

My special thanks to Tipi.build tipi.build logo

 

My special thanks to Take Up Code TakeUpCode 450 60

 

Seminars

I'm happy to give online seminars or face-to-face seminars worldwide. Please call me if you have any questions.

Bookable (Online)

German

Standard Seminars (English/German)

Here is a compilation of my standard seminars. These seminars are only meant to give you a first orientation.

  • C++ - The Core Language
  • C++ - The Standard Library
  • C++ - Compact
  • C++11 and C++14
  • Concurrency with Modern C++
  • Design Pattern and Architectural Pattern with C++
  • Embedded Programming with Modern C++
  • Generic Programming (Templates) with C++

New

  • Clean Code with Modern C++
  • C++20

Contact Me

Modernes C++,

RainerGrimmDunkelBlauSmall

Tags: Concepts

Stay Informed about my Mentoring

 

Mentoring

English 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)

Course: C++ Fundamentals for Professionals

Course: The All-in-One Guide to C++20

Course: Master Software Design Patterns and Architecture in C++

Subscribe to the newsletter (+ pdf bundle)

All tags

Blog archive

Source Code

Visitors

Today 4171

Yesterday 4344

Week 41049

Month 21295

All 12099504

Currently are 148 guests and no members online

Kubik-Rubik Joomla! Extensions

Latest comments