Thursday, 24 July 2008

boost::mpl vs. variadic templates

Boost provides an interesting library, mpl, for metaprogramming at compile time to describe the construction of complex types from basic components. But C++0x, the next version of C++ due sometime in the next two years, has a scheduled feature called variadic templates.

This feature allows you to define class templates like so:

template<typename... T>
class my_template {};

my_template<int, double, my_template<float, char>> var;

But defining an mpl type in terms of one of these is not supported by boost, so I wrote a quick class to translate - although it may not be the fastest way to implement it I'm sure there are simple improvements to be made - if you've got some suggestions, please post them in the comments:


#include <boost/preprocessor/iterate.hpp>
/* The above line is because there is a bug in boost mpl
** which is triggered by gcc trunk where previous compilers
** (both gcc and otherwise) seem to accept some invalid
** code
*/

#include <boost/mpl/vector.hpp>
#include <boost/mpl/list.hpp>
#include <boost/mpl/map.hpp>

using boost::mpl::placeholders::_1;
using boost::mpl::placeholders::_2;
using namespace boost;

template<typename S, class A, typename... T>
struct fold;

template<typename S, class A, typename H, typename... T>
struct fold<S, A, H, T...> :
  fold<mpl::apply<A,S,H>, A, T...>
{};

template<typename S, class A>
struct fold<S, A> :
  S
{};


template<template<typename...> class C, typename S, typename V>
struct append;


template<template<typename...> class C, typename... T>
struct as_mpl :
  fold<C<>, append<C, _1, _2>, T...>
{};



template<typename S, typename V>
struct append<mpl::list, S, V> :
  mpl::push_back<S, V>
{};

template<typename S, typename V>
struct append<mpl::map, S, V> :
  mpl::insert<S, V>
{};

template<typename S, typename V>
struct append<mpl::vector, S, V> :
  mpl::push_back<S, V>
{};

You can add mappings to other mpl containers by specialising append<typename, typename, typename>.

This is used via as_mpl<mpl::vector, type_pack...> and the result is equivalent to mpl::vector<type1, type2, type3>.

No comments: