A Tiny Metaprogramming Library: Extending the Metaphor, entering metafunctions

I know I’m repeating this everytime I write a new article, but it’s one of the key points to make template metaprogramming feasible, which means: TMP is just a functional language. A language with a “Aghhhh, my eyes, please!!! Aaahhhhhg!!!” syntax, but still a functional language.

To start a C++ metaprogramming library the right way, we’d better have a clear idea of what a metafunction is, and how our library represents and manages a metafunction.

Functions

Metafunctions next episode of the Tiny Metaprogramming Library in biicode

What’s a metafunction? Forget that. Enter in our Haskell metaphor first. What’s a function? From Wikipedia:

“[…] a function is a relation between a set of inputs and a set of permissible outputs with the property that each input is related to exactly one output.”

I hope you noticed that’s the mathematical definition of function, instead of a programming-related one. In general, I think calling programming entities functions is not a good idea. They have more to do with old subroutines than with math functions: Most of our code depends on side effects, generates side effects, or depends on reading and changing an external state in some way.

This is C++, but not the C++ most of us usually play with. This is a functional language: There are no side effects, there’s no external state. A function only takes an input, does some transformations on it, producing an output. Functions are mathematical functions, not some kind of prettified subroutines.

Metafunctions

“Something that takes an input, does something with it, producing a result”

This is a struct template parametrized with a type parameter T. Whatever type you instance the template with, the instance struct has a public member type called type equivalent to const T.

For example: If you instance the template with int as parameter:

The member type type will be an alias of const int:

Something that takes an input, T, does something with it (add const), returning and output type.

A template is just a way to represent a function operating on C++ types. That’s what we call metafunction. A function operating on C++ types. Since a type cannot be modified, metafunctions are pure functions, which have no side effects.
The functional language metaphor has much more sense now, right?

Metafunctions in our tiny metaprogramming library

We are playing with the C++ type system, using types or type generators (templates) as elements of our abstract metaprogramming type system.
We will have functions, values, “arrays”, etc. But these are really sets of C++ types.

Since C++ lacks type categories (I’m waiting for the Concepts proposal) there’s no direct way to arrange C++ types into different groups, and use those groups to simulate a high-order type system for our metaprogramming library. Take a look at Boost.Hana for an approximation of type categories for a metaprogramming library, based on tag dispatching.

Instead of building a complex category system like Hana (I’m not a good mathematician, nor an specialist on category theory :) ), my library will be based on some conventions and rules.

Return value of metafunctions

Using a template as a function operating on types, as a metafunction, is not a new concept. Take a look at :

The templates defined there, called type traits, provide information and transformations of given types. For example, std::decay simulates the decay applied to a type when a parameter is passed by value to a function.

To be compatible with the Standard Library, in my Tiny Metaprogramming Library I‘m assuming that any type with a type public member type is a metafunction.

Following that convention, a simple template alias can be a way to get rid of the typename ::type construction, accessing directly to the return value of a metafunction:

Of course this only works for simple expressions. Follow this series to see how this simple but powerful tool evolves.

Parameters of metafunctions

A C++ template can take many kinds of parameters: Types, pointers, values, etc. But let’s keep it simple and only allow type parameters. Why? Because that simplifies a lot our metafunctions.

In fact, a simple variadic template-template parameter like the following represents any function our library can deal with:

Using this little jewel, imagine the next step of the eval tool above.

But you may think: “Manu, I need value parameters too. And template-template parameters”. Don’t worry, we can simulate this using type parameters. Stay tuned for the next post!

Summary

We’ve just learned what does “TMP is a functional language” means. We also learned a way to represent functions operating on C++ types, metafunctions, and two simple conventions for our tiny metaprogramming library:

Any type with a type public member type is considered a metafunction. That member contains the result of the function.
Our metafunctions, represented via templates, can take type parameters only.

In the next post we will see how to use boxing to simulate value parameters and template-template parameters for our metafunctions.


Related Posts