templates

Templates – First Steps

The idea of this post is quite simple. I want to visualize templates and, in particular, the template instantiation process. Thanks to C++ Insights, this visualization is pretty straightforward.

templates

Templates (class templates or function templates) are families of classes or functions. When you instantiate a template, you create a concrete class or a concrete function out of these families of classes or functions. Here are the first straightforward questions I want to answer. For simplicity reasons, I sometimes call a class template a generic class and a function template a generic function.

When should I use a template?

You should use a template when your function or class stands for such a generic idea that this idea is not bound to a concrete type. For example, a function such as max or a container such as vector are usable for many types.

How can I create a template?

I assume you have implemented a function max accepting two ints.

 

Rainer D 6 P2 500x500Modernes C++ Mentoring

Be part of my mentoring programs:

  • "Fundamentals for C++ Professionals" (open)
  • "Design Patterns and Architectural Patterns with C++" (open)
  • "C++20: Get the Details" (open)
  • "Concurrency with Modern C++" (starts March 2024)
  • Do you want to stay informed: Subscribe.

     

    int max(int lhs, int rhs) {
        return (lhs > rhs)? lhs : rhs;
    }
    

     Making a template out of the function is, in general straightforward.

    1. Put the line template <typename T> before the function
    2. Replace the concrete type int with the type parameter T.

    template <typename T>              // (1)
    T max(T lhs, T rhs) {              // (2)
        return (lhs > rhs)? lhs : rhs;
    }
    

    I have to mark two additional remarks. First, instead of the name typename, you can also use class. I strongly suggest typename, because T must not be a class but can be a  type, a non-type, or a template. Second, by convention, we use T as the name for the first type parameter.

    The same procedure also works when transforming a class into a template.

    Now I have come to precisely the point where C++ Insights, provides me with valuable services.

    What happens when I instantiate a template?

    Let instantiate the function template max for int and double.

    template <typename T>
    T max(T lhs, T rhs) {
        return (lhs > rhs)? lhs : rhs;
    }
    
    int main() {
      
        max(10, 5);
        max(10.5, 5.5);
      
    }
    

    C++ Insights provides a deeper insight into this automatic process of template instantiation:

    functionTemplateInstantiation

    The process of template instantiation creates lines 6 – 23. Let me write a few words about the instantiation of the function max for the two ints (lines 6 – 13). Line 6 in the screenshot expresses that line 8 in the source file (max(10, 5)) causes the generation of lines 6 – 13. I assume the first two lines of the compiler-generate code are the most interesting ones.

    template<>
    int max<int>(int lhs, int rhs)
    {
      return (lhs > rhs) ? lhs : rhs;
    }
    

    max is a fully specialized function template for int: max<int>.  The generic part is empty: template<>. The compiler generates out of the family of max-functions one concrete function for int. Does this also mean that the compiler generates a concrete function for each used type?

    What happens, when I instantiate a template more than once for the same type?

    My next example is based on class templates. Here is a simple container two times instantiated for int.

    template <typename T, int N>
    class Array{
     public:
        int getSize() const{
            return N;
        }
     private:
        T elem[N];
    };
    
    int main() {
      
        Array<int, 5> myArr1;  // (1)
        Array<int, 10> myArr2; // (2)
        Array<int, 5> myArr3;  // (3)
      
    }
    

    I instantiated two times Array<int, 5> (lines (1) and (3)) and one time Array<int, 10> (line 2). When you study the output of C++ Insights, you recognize that the second instantiation of Array<int, 5> (line 3) uses the first instantiation already triggered by line (1). Here are the relevant parts of the output.

    classTemplateInstantiation

     

    Are we done with this example? No! There are two additional exciting observations I want to make.

    First, the process of template instantiation is lazy. Second, I use a non-type template parameter.

    Template instantiation is lazy

    Did you recognize that the member function getSize() was not instantiated? Only the declaration of the member function is available. The process of template instantiation is lazy. Meaning if you don’t need it will not be instantiated. This works fine so far that you can use invalid code in a member function. Of course, the member function must not be called. If you don’t believe me, compile the following small program. First, disable line (1), and second, enable line (1).

    // number.cpp
    
    #include <cmath>
    #include <string>
    
    template <typename T>
    struct Number {
    	int absValue() {
            return std::abs(val);
        }
      T val{};
    };
    
    int main() {
      
        Number<std::string> numb;
        // numb.absValue();       // (1)
      
    }
    

    Let’s go back to my previous program and invoke getSize(). Here is the modified main program.

    int main() {
      
        Array<int, 5> myArr1;  
        Array<int, 10> myArr2; 
        Array<int, 5> myArr3;  
        myArr3.getSize();     // (1)
      
    }
    

     Accordingly, the following screenshot shows the compiler-generated code for the member function getSize() (lines 18 – 21).

    classTemplateGetSize

     

    int as a non-type template parameter

    I used in this example two type-parameters in the second one is, in particular, an int. int is an example of a non-type template parameter. Besides int, you can use all integral types, floating-point types (C++20), pointers, or references as non-type template parameters. What happens when I instantiate two arrays of different lengths?

    template <typename T, int N>
    class Array{
     public:
        int getSize() const{
            return N;
        }
     private:
        T elem[N];
    };
    
    int main() {
      
        Array<float, 5> myArr1;
        Array<float, 10> myArr2;
      
    }
    

     You probably guessed it. Two arrays are instantiated. Here is the crucial output from C++ Insights

    classTemplateTwoInts

    This means that both instantiations use different int values create different types.

    What’s next

    After these first steps with templates, I make, in my next post, a deep dive into function templates.

     

    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, 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, 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, Rob North, Bhavith C Achar, Marco Parri Empoli, moon, Philipp Lenk, Hobsbawm, and Charles-Jianye Chen.

    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

    Seminars

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

    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++
    • Clean Code with Modern C++
    • C++20

    Online Seminars (German)

    Contact Me

    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 *