Template Specialization
Templates define the behavior of families of classes or functions. Often it is required that particular types or non-types may be treated special. To support this use case, you can specialize templates.
Let me start this post with the general idea of template specialization. In the next post, I concentrate on the details.
Template Specialization
Templates define the behavior of families of classes and functions. Often it is required that particular types or non-types must be treated special. Therefore, you can fully specialize templates.
Class templates can also be partially specialized. The general or primary template can coexist with partially or fully specialized templates. The member functions and attributes of specialization don’t have to be identical to those of the primary template. The compiler prefers fully specialized to partially specialized templates and partially specialized templates to primary templates.
The following example should clarify my words.
template <typename T, int Line, int Column> // (1) class Matrix; template <typename T> // (2) class Matrix<T, 3, 3>{}; template <> // (3) class Matrix<int, 3, 3>{};
- Primary Template
Line 1 is the primary or general template. The primary template has to be declared before the partially or fully specialized templates. If the primary template is unnecessary, a declaration such as in line 1 is acceptable.
Modernes C++ Mentoring
Do you want to stay informed: Subscribe.
- Partial Specialization
Line 2 follows with the partial specialization. Only class templates support partial specialization. A partial specialization has template parameters and explicitly specified template arguments. In the concrete case, class Matrix<T, 3, 3> T
is the template parameter, and the numbers are the template arguments.
- Full Specialization
Line 3 is the full specialization. Full means that all template arguments are specified and the template parameter list is empty: template <>
in line 3.
Partial versus Full Specialization
To better understand partial and full specialization, I want to present a visual explanation. You may know I studied mathematics, and I had many linear systems of equations to solve.
Think about an n-dimensional space of template parameters. A partial specialization is a subspace in the n-dimensional space, and a full specialization is a point in the n-dimensional space.
I apply my visual explanation to the class template Matrix
and its partial and full specialization. In the primary template (line 1), you can choose a type as a template parameter and two int
values as non-type template parameters. Regarding the partial specialization in line 2, you can only choose the type. This means the 3-dimensional space is reduced to a line. The partial specialization of the primary template Matrix
is, therefore, a subspace of the 3-dimensional space. The full specialization (line 3) is a point in the 3-dimensional space.
What happens when you invoke the templates?
Using the Primary, Partial, and Full Specialization
To remind you, the following specializations of the class Matrix
are given.
template <typename T, int Line, int Column> // (1) class Matrix; template <typename T> // (2) class Matrix<T, 3, 3>{}; template <> // (3) class Matrix<int, 3, 3>{};
The question is: What happens when you instantiate Matrix
for various template arguments? Here are three instantiations, and you see what the compiler creates.
Matrix<int, 3, 3> m1; // class Matrix<int, 3, 3> Matrix<double, 3, 3> m2; // class Matrix<T, 3, 3> Matrix<std::string, 4, 3> m3; // class Matrix<T, Line, Column> => ERROR
m1 uses the entire specialization, m2 uses the partial specialization, and m3 uses the primary template, which causes an error because the definition is missing.
To understand this process, you must remember a few rules. Here are the rules that apply, in particular, to the partial specialization of class templates.
Dependencies between the Template Parameter and the Template Arguments
- The number and sequence of the explicitly specified template arguments (
<T, 3, 3>
) must match the number and sequence of the template parameter list (<typename T, int Line, int Column>
) of the primary template. - If you use defaults for template parameters, you don’t have to provide the template arguments. Only the primary template accepts defaults for template parameters.
Valid Partial Specializations
- The compiler chooses a partial specialization if the template instantiation arguments
(Matrix<double, 3, 3>
) are a subset of the template arguments of the partial specialization (Matrix<T, 3, 3>
).
Chosen Template Specialization
- The compiler finds only one specialization. The compiler uses this specialization.
- The compiler finds more than one specialization. The compiler uses the most specialized one. If this process ends in more than one specialization, the compiler throws an error.
- The compiler finds no specialization. It uses the primary specialization.
Okay, there is one question left I have to answer. What does it mean that a template A
is a more specialized template than another template B
. This is my informal definition.
A template A is more specialized than a template B:
- Template B can accept all arguments that template A can accept.
- Template B can accept arguments that template A cannot accept.
If you want to have it more formal, visit cppreference.com/partial_specialization and go to the subsection about partial ordering.
What’s next?
This post should provide you with the basics about template specialization, but as always, there are more details to it in C++. For example, partial or full specialization behaves like a compile-time if and full specialization of class or function templates is quite similar to ordinary classes or functions.
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!