Template Metaprogramming - How it Works
This post is a cross-post from www.ModernesCpp.com.
In my last post "Template Metaprogramming - How it All Started", I wrote about the roots of template metaprogramming and presented the hello world of template metaprogramming: calculating the factorial of a number at compile time. In this post, I will write about, how template metaprogramming can be used to modify types at compile time.
The factorial program in the last post "Template Metaprogramming - How it All Started" was a nice example but not idiomatic for template metaprogramming. Manipulating types at compile time is typical in template metaprogramming.
Type Manipulation at Compile Time
For example, here is what std::move is conceptionally doing:
static_cast<std::remove_reference<decltype(arg)>::type&&>(arg);
std::move takes its argument arg, deduces its type (decltype(arg)), removes its reference (std::remove_reverence), and casts it to an rvalue reference (static_cast<...>::type&&>). Essentially,
std::move is an rvalue reference cast. Now, move semantics can kick in.
How can a function remove constness from its argument?
// removeConst.cpp
#include <iostream>
#include <type_traits>
template<typename T >
struct removeConst {
using type = T; // (1)
};
template<typename T >
struct removeConst<const T> {
using type = T; // (2)
};
int main() {
std::cout << std::boolalpha;
std::cout << std::is_same<int, removeConst<int>::type>::value << '\n'; // true
std::cout << std::is_same<int, removeConst<const int>::type>::value << '\n'; // true
}
I implemented removeConst the way std::remove_const is probably implemented in the type-traits library. std::is_same from the type-traits library helps me to decide at compile-time if both types are the same. In case of removeConst<int> the primary or general class template kicks in; in case of removeConst<const int>, the partial specialization for const T applies. The critical observation is that both class templates return the underlying type in (1) and (2) via the alias type. As promised, the constness of the argument is removed.
There are additional observations:
Let me step back and write about template metaprogramming for a more conceptual view.
More Meta
At run time, we use data and functions. At compile time we use metadata and metafunctions. Quite logically, it's called meta because we do metaprogramming.
Metadata
Metadata are values that metafunctions us at compile time.
There are three types of values:
You can read more about the three types of values in my previous post "Alias Templates and Template Parameters".
Metafunctions
Meta functions are functions that are executed at compile time.
Admittedly, this sounds strange: Types are used in template metaprogramming to simulate functions. Based on the definition of metafunctions, constexpr functions that can be executed at compile-time, are also metafunctions. The same holds for consteval functions in C++20.
Here are two metafunctions.
template <int a , int b>
struct Product {
static int const value = a * b;
};
template<typename T >
struct removeConst<const T> {
using type = T;
};
The first meta-function Product returns a value and the second one removeConst returns a type. The name value and type are just naming conventions for the return values. If a meta-function returns a value, it is called value; if it returns a type, it is called type. The type-traits library follows exactly this naming convention.
It is quite enlightening to compare functions with metafunctions.
领英推荐
Functions versus Metafunctions
The following function power and the metafunction Power calculate pow(2, 10) at run time and compile time.
// power.cpp
#include <iostream>
int power(int m, int n) {
int r = 1;
for(int k = 1; k <= n; ++k) r *= m;
return r;
}
template<int m, int n>
struct Power {
static int const value = m * Power<m, n-1>::value;
};
template<int m>
struct Power<m, 0> {
static int const value = 1;
};
int main() {
std::cout << '\n';
std::cout << "power(2, 10)= " << power(2, 10) << '\n';
std::cout << "Power<2,10>::value= " << Power<2, 10>::value << '\n';
std::cout << '\n';
}
This is the main difference:
I elaborate more on this comparison in the upcoming post about constexpr and consteval functions. Here is the output of the program.
power is executed at run time and Power at compile time, but what is happening in the following example??
// powerHybrid.cpp
#include <iostream>
template<int n>
int Power(int m){
??? return m * Power<n-1>(m);
}
template<>
int Power<0>(int m){
??? return 1;
}
int main() {
?? ?
??? std::cout << '\n';
??? std::cout << "Power<0>(10): " << Power<0>(20) << '\n';
??? std::cout << "Power<1>(10): " << Power<1>(10) << '\n';
??? std::cout << "Power<2>(10): " << Power<2>(10) << '\n';
?? ?
??? std::cout << '\n';
}
The question is obviously: Is Power a function or a metafunction? I promise the answer to this question gives you more insight.
What's next?
In my next post, I analyze the function/meta function Power and introduce the type-traits library. The type traits library is idiomatic for compile-time programming in C++.
?
Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, Marko, G Prvulovic, Reinhold Dr?ge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Animus24, Jozo Leko, John Breland, espkk, Louis St-Amour, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Kris Kafka, Mario Luoni, Neil Wang, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Tobi Heideman, Daniel Hufschl?ger, Red Trip, Alexander Schwarz, Tornike Porchxidze, Alessandro Pezzato, Evangelos Denaxas, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Dimitrov Tsvetomir, Leo Goodstadt, Eduardo Velasquez, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, and Michael Young.
Thanks in particular to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, and Rusty Fleming.
My special thanks to Embarcadero
?
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.
New
Contact Me
Entrepreneur, Leader, Architect, Full-Stack Extreme Virtuoso: Business Analysis, Cyber Security, Data Science. ITIL BPM SLM Expert bringing Modern Approaches to drive Business Processes.
3 年This is going to be exciting! The power of template metaprogramming is phenomenal :)