#include <boost/preprocessor/arithmetic/add.hpp>
#include <boost/preprocessor/arithmetic/sub.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/control/expr_if.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#include <iostream>
#include <typeinfo>

struct D {}; // default type

template< typename, typename > struct common_type_helper;
template<> struct common_type_helper< D, D > { typedef D type; };
template< typename T > struct common_type_helper< D, T > { typedef T type; };
template< typename T > struct common_type_helper< T, D > { typedef T type; };
template< typename T > struct common_type_helper< T, T > { typedef T type; };

#define COMMON_TYPE_NUM_ARGS 8

#define COMMON_TYPE_TEMPLATE_PARM(z,n,unused)                                      \
  typename BOOST_PP_CAT(T,n)BOOST_PP_EXPR_IF(n,=D)
#define COMMON_TYPE_AUX_TYPEDEF(z,n,unused)                                        \
  typedef typename common_type_helper<                                             \
    BOOST_PP_CAT(t,n),BOOST_PP_CAT(T,BOOST_PP_ADD(n,2))                            \
  >::type BOOST_PP_CAT(t,BOOST_PP_ADD(n,1));

template<BOOST_PP_ENUM(COMMON_TYPE_NUM_ARGS,COMMON_TYPE_TEMPLATE_PARM,~)>
struct common_type
{
  typedef typename common_type_helper<T0,T1>::type t0;
  BOOST_PP_REPEAT(BOOST_PP_SUB(COMMON_TYPE_NUM_ARGS,2),COMMON_TYPE_AUX_TYPEDEF,~)
  typedef BOOST_PP_CAT(t,BOOST_PP_SUB(COMMON_TYPE_NUM_ARGS,2)) type;
};

int main()
{
  std::cout << typeid( common_type< D, D, D, D, D, D, D, D >::type ).name() << std::endl;
  std::cout << typeid( common_type< D, int, D, D, D, D, int, D >::type ).name() << std::endl;
  std::cout << typeid( common_type< bool, bool, bool, bool, bool, bool, bool, bool >::type ).name() << std::endl;
  // std::cout << typeid( common_type< D, char, double, D, D, D, D, D >::type ).name() << std::endl;
}

