As some of you know, in November I conducted a presentation "Metaprogramming in C++: from 70's to C++17" at Code::Dive conference. One of things that I mentioned about C++ templates was what actually can be a template. One of the things that I covered was template variables from C++14. In this post I'd like to present them in action.

However, before I move forward I'd like to see if you can spot the mistake I made during the presentation. I said that following things can be templated in C++. Can you point out the mistake?
  • C++98: class, structure, (member) function
  • C++11: using directive
  • C++14: variable
Do you see it?

The question is tricky. It turns out that since C++98 it was possible to make template union as well. I don't know how about you, but I haven't use union for more than five years from now. I saw it recently as a storage for optional class, though. It's a rare thing, but definitely worth knowing.

Okay, enough off-topic. Let's get back to template variables from C++14. This feature was introduced with N3651 proposal. The proposal argues that in C++ we should have legal mechanisms instead of workarounds like static const variable defined in a class, or value returned from constexpr function.

But what are the use cases of this? The proposal gives us example use case presented below.

1 template <typename T>
2 constexpr T pi = T(3.1415926535897932385);
3
4 template <typename T>
5 T area_of_circle_with_radius(T r) {
6 return pi<T> * r * r;
7 }

Although this is complete example it was quite hard for me to figure out other use cases in two shakes. The breakthrough came with this commit to Clang's libcxx library. It used this very new feature to make simpler versions of type_traits templates. I hope that following listing is illustrating this well.

 1 namespace ex = std::experimental;
2
3 // ...
4 {
5 typedef void T;
6 static_assert(ex::is_void_v<T>, "");
7 static_assert(std::is_same<decltype(ex::is_void_v<T>), const bool>::value, "");
8 static_assert(ex::is_void_v<T> == std::is_void<T>::value, "");
9 }
10 {
11 typedef int T;
12 static_assert(!ex::is_void_v<T>, "");
13 static_assert(ex::is_void_v<T> == std::is_void<T>::value, "");
14 }
15 {
16 typedef decltype(nullptr) T;
17 static_assert(ex::is_null_pointer_v<T>, "");
18 static_assert(std::is_same<decltype(ex::is_null_pointer_v<T>), const bool>::value, "");
19 static_assert(ex::is_null_pointer_v<T> == std::is_null_pointer<T>::value, "");
20 }
21 // ...

So from this commit onward we are able to write more concise and more readable code in one shot. This nice addition to C++ is practical not only for template variables, but also for making things easier.