C++20: Concepts - Syntactic Sugar

Contents[Show]

Today, my post is not about something new to concepts. It's about syntactic sugar. I write about abbreviated function templates. What? Abbreviated functions templates allow a sweet way to define templates.

 

TimelineCpp20Concepts

First of all, here is the definition of syntactic sugar from Wikipedia:

In computer science, syntactic sugar is syntax within a programming language that is designed to make things easier to read or to express. It makes the language "sweeter" for human use: things can be expressed more clearly, more concisely, or in an alternative style that some may prefer.

The syntactic sugar I'm writing today is called abbreviated function templates.

Abbreviated Function Templates

I wrote in my last post to concepts C++20: Concepts, the Placeholder Syntax that we have since C++14 a significant asymmetry: generic lambdas introduced a new way to define function templates. Just use auto as a function parameter. On the contrary, you can not use auto as a function parameter to get a function template.

// genericLambdaFunction.cpp

#include <iostream>
#include <string>

auto addLambda = [](auto fir, auto sec){ return fir + sec; }; // (1)

auto addFunction(auto fir, auto sec){ return fir + sec; }     // (2)

int main(){

    std::cout << std::boolalpha << std::endl;

    std::cout << addLambda(1, 5) << " " << addFunction(1, 5) << std::endl;
    std::cout << addLambda(true, 5) << " " << addFunction(true, 5) << std::endl;
    std::cout << addLambda(1, 5.5) << " " << addFunction(1, 5.5) << std::endl;
    
    const std::string fir{"ge"};
    const std::string sec{"neric"};
    std::cout << addLambda(fir, sec) << " " << addFunction(fir, sec) << std::endl;

    std::cout << std::endl;

}

 

 The clang compiler speaks a clear language when I try to compile this program with the C++14 standard.

genericLambdaFunction

How strange! I can use auto as return type and for the function parameters in a lambda (line 1), but I can only use auto as the return type of a function (line 2).

I'm happy to say. This weird behaviour is gone with C++20 and the unification is, also, extended to concepts.

 

// conceptsIntegralVariationsDraft.cpp

#include <type_traits>
#include <iostream>

template<typename T>                                  // (1)
concept Integral = std::is_integral<T>::value;       

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

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

template<Integral T>                                  // (4)
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){ // (5)
    if( b == 0 ){ return a; }
    else return gcd(b, a % b);
}

auto gcd4(auto a, auto b){                            // (6)
    if( b == 0 ){ return a; }
    return gcd(b, a % b);
}

int main(){

    std::cout << std::endl;

    std::cout << "gcd(100, 10)= "  <<  gcd(100, 10)  << std::endl;
    std::cout << "gcd1(100, 10)= " <<  gcd1(100, 10)  << std::endl;
    std::cout << "gcd2(100, 10)= " <<  gcd2(100, 10)  << std::endl;
    std::cout << "gcd3(100, 10)= " <<  gcd3(100, 10)  << std::endl;
    std::cout << "gcd4(100, 10)= " <<  gcd3(100, 10)  << std::endl; 

    std::cout << std::endl;

}

Let me describe in a few words the already known stuff for my previous posts to concepts. Line 1 defines the concept Integral. gcd - gcd2 (lines 2 - 4) use the concept in various ways. gcd used the requires clause, gcd1 the so-called trailing requires clause, and gcd2 constrained template parameters.

With gcd3, the syntactic sugar starts. The function declaration Integral auto gcd3(Integral auto a, Integral auto b), requires from its type parameters that they support the concept Integral. This syntactic form is the new way to use a concept and to get a function template that is equivalent to the previous versions gcd - gcd2.

The syntactic form of gcd3 and gcd4 is called abbreviated function templates. Integral auto in the declaration of gcd3 is a  constrained placeholder (concept), but you can also use an unconstrained placeholder (auto)  in a function declaration such as in gcd4 (line 6). Before I make a few additional remarks to this new syntax, here is the output of the program:

conceptsIntegralVariationsDraft

Using an unconstrained placeholder (auto) in a function declaration generates a function template. The following two functions add are equivalent:

template<typename T, typename T2>
auto add(T fir, T2 sec){
    return fir + sec;
}

auto add(auto fir, auto sec){
    return fir + sec;
}

The key observation is, that both arguments can have different types. The same holds for concepts.

 

template<Arithmetic T, Arithmetic T2>                           // (1)
auto sub(T fir, T2 sec){
    return fir - sec;
}

Arithmetic auto sub(Arithmetic auto fir, Arithmetic auto sec){  // (2)
    return fir - sec;
}

 

The function sub requires from its arguments fir and sec,  that both support the concept Arithmetic. This means, you can invoke sub(5.5, 5), and it works with the function template (line 1) and the function (line 2). In both cases, the return type is deduced accordingly to arithmetic conversions rules. The concept Arithmetic requires that fir and sec are either integral or floating-point numbers. Here is a straightforward implementation based on the type-traits function std::is_arithmetic.

template<typename T> 
concept Arithmetic = std::is_arithmetic<T>::value; 

A Difference between Concepts TS and Concepts Draft

I explicitly mentioned that both arguments could have different types with the Concepts Draft because this is different from the previous concepts syntax, which is, supported by GCC. The previous syntax was based on the concepts TS (technical specification). In this syntax, the types of fir and sec have to be the same, and a call of the function sub(5.5, 5) would fail. Additionally, the previous syntax required no additional auto when concepts were used and the definition of concepts was slightly more verbose.

// conceptsArithmeticTS.cpp

#include <type_traits>
#include <iostream>

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

Arithmetic sub(Arithmetic fir, Arithmetic sec){
    return fir - sec;
}

int main(){

    std::cout << std::endl;

    std::cout << "sub(6, 5): " << sub(6, 5) << std::endl;      // (1)
    std::cout << "sub(5.5, 5): " << sub(5.5, 5) << std::endl;  // (2)

    std::cout << std::endl;

}

 

Because of line 2, the compilation of the program fails with the concepts TS.

conceptsArithmeticTS

Overloading

The abbreviated function templates syntax behaves as expected. The new syntax support overloading. As usual, the compiler chooses the best fitting overload.

// conceptsOverloading.cpp

#include <type_traits>
#include <iostream>

template<typename T>
concept Integral = std::is_integral<T>::value;

void overload(auto t){
    std::cout << "auto : " << t << std::endl;
}

void overload(Integral auto t){
    std::cout << "Integral : " << t << std::endl;
}

void overload(long t){
    std::cout << "long : " << t << std::endl;
}

int main(){
    
    std::cout << std::endl;

    overload(3.14);             // (1)
    overload(2010);             // (2)
    overload(2020l);            // (3)
    
    std::cout << std::endl;
    
}

When invoked with a double (line 1), an int (line 2), or a long int (line 3), the best fitting overload is chosen.

conceptOverloading

What's next?

Two pieces are still missing in my series to concepts and are, therefore, the topic of my next posts — the definition of concepts and the so-called template introduction, which is part of the concept TS.

 

 

 

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

Visitors

Today 4012

All 3216637

Currently are 240 guests and no members online

Kubik-Rubik Joomla! Extensions

Latest comments