I am actually trying to see if I can get a minimal library that supports the very few operations I use from boost::fusion.
Here is what I have so far...
Seems to be doable with fully-fledged lists (that means head, tail and cons operations) and recursion. Tested with a snapshot of GCC 4.7, all the std
stuff is from <type_traits>
:
struct nil {};
template<typename T>
struct is_nil: std::is_same<T, nil> {};
template<typename... T>
struct and_: std::true_type {};
template<typename First, typename... Rest>
struct and_<First, Rest...>
: std::integral_constant<
bool
, First::value && and_<Rest...>::value
> {};
template<typename T>
struct not_
: std::integral_constant<bool, !T::value> {};
template<typename... T>
struct typelist;
template<typename First, typename Second, typename... Rest>
struct typelist<First, Second, Rest...> {
typedef First head;
typedef typelist<Second, Rest...> tail;
};
template<typename Last>
struct typelist<Last> {
typedef Last head;
typedef nil tail;
};
template<typename T, typename List>
struct cons;
template<typename T, typename... Ts>
struct cons<T, typelist<Ts...>> {
typedef typelist<T, Ts...> type;
};
// workaround for:
// sorry, unimplemented: cannot expand '...' into a fixed-length argument list
template<template<typename...> class Template, typename... T>
struct gcc_workaround {
typedef Template<T...> type;
};
namespace detail {
template<typename Sfinae, typename... Lists>
struct zip;
template<typename... Lists>
struct zip<
typename std::enable_if<and_<is_nil<typename Lists::tail>...>::value>::type
, Lists...
> {
typedef typelist<typelist<typename Lists::head...>> type;
};
template<typename... Lists>
struct zip<
typename std::enable_if<and_<not_<is_nil<typename Lists::tail>>...>::value>::type
, Lists...
> {
typedef typename cons<
typelist<typename Lists::head...>
, typename gcc_workaround<zip, void, typename Lists::tail...>::type::type
>::type type;
};
} // detail
template<typename... Lists>
struct zip: detail::zip<void, Lists...> {};
You might want to add error checking to all this (I'm thinking of invalid instantiations that are currently simply left as incomplete types). Frankly given the amount of time it took me to figure this out, I'd suggest sticking with Boost.MPL. Things like lazy evaluation (with which I wouldn't have needed to do the SFINAE stuff) are a boon and I'd don't like reinventing them. Plus the day it's C++11 enabled you reap the best of both worlds.
I forgot to mention that Boost.MPL also has the advantages of genericity. It can work on any type that satisfies one of its sequence concept (it's also possible to non-intrusively adapt a preexisting type), whereas you force the use of typelist
.
This is the shortest implementation I've discovered:
template <typename...> struct typelist { };
template <typename A,typename B> struct prepend;
template <typename A,typename B> struct joincols;
template <typename...> struct zip;
template <typename A,typename... B>
struct prepend<A,typelist<B...> > {
typedef typelist<A,B...> type;
};
template <>
struct joincols<typelist<>,typelist<> > {
typedef typelist<> type;
};
template <typename A,typename... B>
struct joincols<typelist<A,B...>,typelist<> > {
typedef typename
prepend<
typelist<A>,
typename joincols<typelist<B...>,typelist<> >::type
>::type type;
};
template <typename A,typename... B,typename C,typename... D>
struct joincols<typelist<A,B...>,typelist<C,D...> > {
typedef typename
prepend<
typename prepend<A,C>::type,
typename joincols<typelist<B...>,typelist<D...> >::type
>::type type;
};
template <>
struct zip<> {
typedef typelist<> type;
};
template <typename A,typename... B>
struct zip<A,B...> {
typedef typename joincols<A,typename zip<B...>::type>::type type;
};