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.
“[…] 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.
“Something that takes an input, does something with it, producing a result”
using type = const T;
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
For example: If you instance the template with
int as parameter:
using a = add_const<int>
The member type
type will be an alias of
using b = add_const<int>::type; //b is const int
Something that takes an input,
T, does something with it (add
const), returning and output
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
using ptr = std::decay<int>::type;
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:
alias eval = typename F::type;
alias myint = eval<std::remove_reference<int&>>;
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:
template<typename... ARGS> class F
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!
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:
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.