Templates - First Steps

Contents[Show]

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.

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.

 

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.

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, 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

Comments   

+2 #1 Kiran 2021-05-05 01:43
Thanks for putting it so clear and detailed way
Eagerly waiting for next post in this series
Quote
0 #2 Pramod Tikare 2021-05-11 11:03
Nice article. I have got 2 feedbacks.
1. It makes sense to add line numbers to your code snippet, since cppinsights displays the line number corresponding to the generic function.

2. In the text, you mention non-type type parameters multiple times. I assume this is a typo error for non-type template parameter.

Thanks!
Quote
0 #3 Sandor 2021-08-03 11:16
Thanks for this nice article.

While it's true that by convention we use T as the name for the first template parameter, I think in-non trivial cases we should go for more descriptive names to improve readability.
Quote

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 3773

Yesterday 4371

Week 39580

Month 169705

All 12057471

Currently are 162 guests and no members online

Kubik-Rubik Joomla! Extensions

Latest comments