, 3 min read
Book Review : Template Metaprogramming with C++
I have spent the last few years programming often in C++. The C++ langage is probably one of the hardest to master. I still learn something new every week. Furthermore, C++ is getting upgrades all the time: C++17 was a great step forward and C++20 brings even more exiting improvments.
In C++, we often use ‘templates’. As the name suggests, they allow us to create C++ functions and classes from a generic recipe. For example, the following template allows us to create functions that sum up two values:
template <class T>
T f(T x, T y) {
return x + y;
}
It gets automatically instantiated when you need it. The following function will return the sum of two integers.
int g(int x, int y) {
return f(x,y);
}
Templates are very powerful. They allow us to create highly efficient code, because everything happens at compile time: the optimizer can do it is work. With great power, comes great responsibility: templates can be infuriating since they may lead to unreadable error messages, and they can greatly increase the compile time. I use templates sparingly when programming in C++.
I spent the last few weeks reading Template Metaprogramming with C++ by Marius Băncilă. It is currently 50$ on Amazon.
Though, technically, the book is about advanced ‘template’ techniques, it is much more broad and practical. It is one of the ‘good programming books’. If you are an experienced C++ programmer, you should give it a peek. It is full of practical code.
The book reminded me of the following features.
Explicit instantiation declaration: In my example above, the template f
with type int
gets compiled as soon as I invoke it. In that particular case, it is not worrisome. However, it can be helpful to pre-compile the functions to reduce compile time in large projects, involving large pieces of code. We typically achieve the desire results in C and C++ by separating function declaration (put in a header file) and function definition (put in a source file). It is somewhat trickier to do with templates. Yet we can do so by putting the following line in the header:
extern template int f(int,int);
Followed by the following in a source file:
template int f(int,int);
And voilà!
Lambda templates. It is cumbersome in C and C++ to define a function. In C++, you can create ‘lambdas’ which are effectively locally defined functions. For example, the following code first defines an ‘addition’ function (called lambda) and then it applies it to add two numbers:
int g(int x, int y) {
auto lambda = [](int x, int y) -> int { return x + y; };
return lambda(x, y);
}
Up until recently, you could not mix templates and lambdas, but now you can with C++20:
int g(int x, int y) {
auto lambda = []<class T>(T x, T y) -> T { return x + y; };
return lambda(x, y);
}
Variable templates. Sometimes you need constants that depend on a type. For example, the number pi might different depending on the precision of the type you are using. That is where variable templates shine:
template <typename T>
constexpr T PI = T(3.1415926535897932384626433832795028841971693993751);
std::cout << PI<double> << std::endl;
std::cout << PI<float> << std::endl;
There is plenty more to explore in Băncilă’s book.
I posted some code examples on GitHub.
Disclosure: I got a free copy of the book from the editor in exchange for a promise that I would do a review if I liked the book. I did not agree beforehand to produce a positive review. I do not get paid if you buy the book.