A Tiny Metaprogramming Library: Boxing – Part 1

A Tiny Metaprogramming Library episode 3:

Last time we introduced the mathematical concept of function as an entity that takes an input, generating an output. In that process, the function does not change any external state.

We also talked about metafunctions, a way to represent functions operating on C++ types using C++ templates.

After the theory, we followed with some conventions about the specific implementation of metafunctions in our tiny metaprogramming library. We decided that:

  • Any type with a type public member type is considered a metafunction, where type represents the result of that metafunction.That means to take the result of a metafunction we should say typename F::type in most of the situations. We introduced a simple tool tml::eval to help a bit.
  • Our metafunctions are templates, but these are constrained to take type parameters only.

In this post we will learn how to use boxing to pass value parameters as type parameters for our metafunctions. This is not something new but a way to understand what std::integral_constant, one of the fundamentals of <type_traits>, is and what can be used for.
Tiny Metaprogramming library episode 3: boxing.

Boxing values

We need a way to represent a value with a type. This is simple: Put a static public constant on a type, meaning the value of that constant is the value represented by that type. Something like this:

Here we defined a template value_holder, which takes a type and a value of that type as parameters. Then it defines a public compile-time constant (Note the constexpr, not strictly needed, but more elegant than const or the old enum hack) which holds the value V. After instantiating that template, you can get the value the instance holds via its value public member constant:

For the C++11 newbies, static_assert() is like the good old C assert(), but at compile-time.

Now we can implement simple metafunctions operating on “values”:

Now let’s get, let’s deeply understand, what we have written above: We are not just computing integer addition at compile-time, but hacking the C++ type system to do some computations for us! Cool, isn’t?

Of course is not that simple. We are doing C++ template metaprogramming, not playing with Java generics.

The type of the result

I’m sure you noticed that where I should place the type of the result value inside the add metafunction, I just wrote ¿?. As we have seen, value_holder expects the type of the value first, then the value.

But, what’s the type of a::value + b::value?

Hopefully, the old days of C++98/03 are gone, and C++11 ships with a tool to solve our problem easily: decltype().

decltype() takes an expression and returns the type of the result of evaluating that expression.

“The type of the result of evaluating that expression” How can the C++ compiler know what that type is if the expression is not (And usually it cannot be) evaluated at compile time?

Remember that we are working on a language with a strict and static type system. This is not javascript. A C++ compiler knows perfectly the type of every expression you wrote in your program. That’s a lot of information, and the source of most of the sorcery modern optimizers apply to your C++ programs.

So our addition metafunction should be:

The ::value member. It’s really a good idea?

Well, that depends on your point of view. Having a boxing type T and getting its value with ::value is so convenient:

Sorry, I had to write an example using C++14 variable-templates :)

But consider our functional metaphor. The add metafunction defined above has its result written like this:

which works perfectly with value_holder-like things.

But now I want to do a = 1 + (2 + 3):

Ignore the Haskell-bastard syntax… Hopefully along this series we will learn some mechanisms to improve this. As usually, stay tuned.

Of course this does not compile. add has no value member. I know, I should evaluate the metafunction first:

But we are trying to make TMP something readable with our Tiny Metaprogramming Libraries, and one of the points we should improve is metafunction evaluation. No more chained typename ::types please.

But there’s a problem here: Even if we develop a generic tool for expression evaluation (Do you remember tml::eval?) we cannot write nested metafunctions if those are implemented in that way:

This will never work since to evaluate that expression, it should be instanced first. And add is expecting ::value in its operands. That will be a problem in the future, keep it in mind. We will see different approaches to solve this.

Plz send teh codez

I you check my Tiny Metaprogramming Library, I currently have two files: core/eval.hpp and core.hpp. The first is the header containing tml::eval and the second is an umbrella header with all the core features of the library.

As part of the library core features, I will add a new header, integral_constant.hpp, with a template similar to value_holder example given here. Let’s keep it simple and just alias std::integral_constant :)

What’s next?

Now we are able to pass values to our type-only metafunctions, using the standard std::integral_constant template.

The next step is to write such thing for templates, something that takes a template and holds it on a type. Of course that boxed template should be instantiable.

Are you ready?


Related Posts
  • icatallo

    Nice article. using result should probably read using type

    • Manu343726

      Thanks for the feedback. On my first attempt to write a metaprogramming library, I chose result instead of type. That was a bad decision (I had to take both into account on tml::eval implementation, to make it compatible with STL type traits) and the reason why I’m using type on this series. But have been two years writing result, it’s hard to me to change the habit :)

      • icatallo

        Yep. I believe that type originates from the book ‘boost and beyond’. Its adoption in the boost MPL library has then caused type to be promoted also in the STL.