future

C++ Core Guidelines: Rules for Templates and Generic Programming

I this post I give an introduction to the rules for generic programming in C++. Generic programming is, from my point of view, the outstanding feature and the future of C++. Hence it follows that this and the upcoming posts are about the future of C++.

 

future

First, I use the terms templates and generic programming, whatever fits best. Of course, I know that templates are just a way to write generic code. I assume you know what templates in C++ are, but you don’t know what generic programming means. Here is my favorite definition from Wikipedia.

  • Generic programming is a style of computer programming in which algorithms are written in terms of types to-be-specified-later that are then instantiated when needed for specific types provided as parameters.

The rules to templates are about the current C++17 and the upcoming C++20 standard. Of course, I assume that we will get concepts with C++20. In sum, there are 100 rules to concepts, template interfaces, template definitions, template hierarchies, variadic templates, and template metaprogramming. The first five rules are pretty general.

In the examples, concepts are often commented on. If you want to try them out, comment them in and use at least a  GCC 6.1 compiler with the flag -fconcepts or an online compiler: constraints and concepts.

Concepts are predicates on templates that are evaluated at compile time. They should model semantic categories such as Number, Callable, Iterator or Range but not syntactic restrictions such as HasPlus, or IsInvocable. Here are more details of concepts.

Maybe, you are puzzled by the difference between semantic categories and syntactic restrictions. The first rule helps to distinguish both terms.

T.1: Use templates to raise the level of abstraction of code

Here is the example from the guidelines, but I called the second concept Addable.

Rainer D 6 P2 500x500

 

Rainer D 6 P2 500x500Modernes C++ Mentoring

  • "Fundamentals for C++ Professionals" (open)
  • "Design Patterns and Architectural Patterns with C++" (open)
  • "C++20: Get the Details" (open)
  • "Concurrency with Modern C++" (open)
  • "Generic Programming (Templates) with C++": October 2024
  • "Embedded Programming with Modern C++": October 2024
  • "Clean Code: Best Practices for Modern C++": March 2025
  • Do you want to stay informed: Subscribe.

     

    template<typename T>
        // requires Incrementable<T>
    T sum1(vector<T>& v, T s)
    {
        for (auto x : v) s += x;
        return s;
    }
    
    template<typename T>
        // requires Addable<T>
    T sum2(vector<T>& v, T s)
    {
        for (auto x : v) s = s + x;
        return s;
    }
    

     

    What is wrong with both concepts? Both concepts are too specific. Both concepts are based on specific operations, such as the increment and the + operation. Let’s go one step further from the syntactic constraints to the semantic category Arithmetic.

     

    template<typename T>
        // requires Arithmetic<T>
    T sum(const vector<T>& v, T s)
    {
        for (auto x : v) s += x;
        return s;
    }
    

     

    Now, the algorithm has minimal requirements. Hold: the algorithm is better but not good. It only works on a std::vector. It’s generic on the type of the container but not on the container. Let me generalize the sum algorithm once more.

     

    template<typename Cont, typename T>
        // requires Container<Cont>
        // && Arithmetic<T>
    T sum(const Cont& v, T s)
    {
        for (auto x : v) s += x;
        return s;
    }
    

     

    Now, it’s fine. Maybe you prefer a more concise definition of the sum. Instead of the keyword typename, I use the concepts directly.

    template<Container Cont, Arithmetic T>
    T sum(const Cont& cont, T s){
        for (auto x : cont) s += x;
        return s;
    }
    

     

    T.2: Use templates to express algorithms that apply to many argument types

    When you study the first overload of std::find at cppreference.com, it looks like this:

    template< class InputIt, class T >
    InputIt find( InputIt first, InputIt last, const T& value );
    

     

    The types of Iterators are encoded in their names: InputIt stands for input iterator and means that the iterator can read from the pointed-to element. There are two issues with this declaration:

    1. The requirements for the iterators are encoded in the name. This reminds me of the infamous Hungarian notation
    2. No requirement stated that the pointed-to element can be compared with the value.

    Let me use the iterator concept directly:

    template<Input_iterator Iter, typename Val>
        // Equality_comparable<Value_type<Iter>, Val>
    Iter find(Iter b, Iter e, Val v)
    {
        // ...
    }
    

     

    T.3: Use templates to express containers and ranges

    Okay. It’s pretty obvious to make a container generic. For example, here is a Vector.

     

    template<typename T>
        // requires Regular<T>
    class Vector {
        // ...
        T* elem;   // points to sz Ts
        int sz;
    };
    
    Vector<double> v(10);
    v[7] = 9.9;
    

     

    Okay, fine, but when is a user-defined type T regular? The document Fundamentals of Generic Programming defines a type T regular if it behaves like a built-in type such as bool, int, or double. I should mention it. The paper Fundamentals of Generic Programming is from James C. Dehnert and Alexander Stepanow. I assume you already know Alexander Stephanow by name. He is the well-known father of the Standard Template Library.

    The document states that a type T is called regular if it defines the following operations:

    regular

    The equality, inequality, and ordering operation on T could be defined component-wise.

    What’s next?

    My original plan was to write about rule 5: T.5: Combine generic and OO techniques to amplify their strengths, not their costs. I changed my plan because rule 5 is relatively short and mentioned type erasure as a use-case for this technique. Type erasure is a technique to represent various concrete types through a single interface. Type erasure with templates could not be explained in a few sentences; therefore, I will write in my next post about this challenging technique.

     

    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, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, 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, Stephen Kelley, Kyle Dean, Tusar Palauri, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, Wolfgang Fütterer, Matthias Grün, Phillip Diekmann, Ben Atakora, Ann Shatoff, Rob North, Bhavith C Achar, Marco Parri Empoli, Philipp Lenk, Charles-Jianye Chen, Keith Jeffery, Matt Godbolt, and Honey Sukesan.

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

    My special thanks to Embarcadero
    My special thanks to PVS-Studio
    My special thanks to Tipi.build 
    My special thanks to Take Up Code
    My special thanks to SHAVEDYAKS

    Modernes C++ GmbH

    Modernes C++ Mentoring (English)

    Do you want to stay informed about my mentoring programs? Subscribe Here

    Rainer Grimm
    Yalovastraße 20
    72108 Rottenburg

    Mobil: +49 176 5506 5086
    Mail: schulung@ModernesCpp.de
    Mentoring: www.ModernesCpp.org

    Modernes C++ Mentoring,

     

     

    0 replies

    Leave a Reply

    Want to join the discussion?
    Feel free to contribute!

    Leave a Reply

    Your email address will not be published. Required fields are marked *