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 (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.
- Put the line
template <typename T>
before the function - Replace the concrete type
int
with the type parameterT
.
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.
Modernes C++ Mentoring
Do you want to stay informed: Subscribe.
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:
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.
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).
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
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, 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,and Matt Godbolt.
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)
- Embedded
Programmierung mit modernem C++ (24. Sep. 2024 bis 26.
Sep. 2024)
Contact Me
- Mobil: +49 176 5506 5086
- Mail: schulung@ModernesCpp.de
- German Seminar Page: www.ModernesCpp.de
- Mentoring Page: www.ModernesCpp.org
Modernes C++ Mentoring,
Leave a Reply
Want to join the discussion?Feel free to contribute!