Search code examples
c++c++11tuplesboost-mpl

How to use std::tuple types with boost::mpl algorithms?


The boost::mpl algorithms seem not to be able to work on std::tuple types out of the box, e.g., the following does not compile (boost-1.46.0, g++ snapshot 2011-02-19):

#include <tuple>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/contains.hpp>

namespace mpl=boost::mpl;

typedef mpl::vector<int,float,bool> types;
static_assert(mpl::contains<types, float>::value, "vector contains bool");

typedef std::tuple<int,float,bool> types2;
// the following does not compile:
// error: no class template named ‘apply’ in ‘struct boost::mpl::contains_impl<boost::mpl::non_sequence_tag>’
static_assert(mpl::contains<types2, float>::value, "tuple contains bool");

What is the easiest way to make the boost::mpl algorithms work on std::tuple?

  • Does evtl. boost::fusion provide this functionality (as it does so for boost::tuple)?
  • If not, would it be possible to carry over the fusion implementation for boost::tuple to std::tuple easily?
  • If not either, do I really have to implement all the intrinsic metafunctions listed in the MPL documentation or which ones would be sufficient? (The docs only says "many of intrinsic metafunctions offer a default implementation that will work in majority of cases", but it is not clear which ones exactly. And some tests with just providing begin and end did not lead me anywhere).

Solution

  • Converting from std::tuple to boost types and back seems to be the easiest way

    #include <iostream>
    #include <tuple>
    #include <type_traits>
    #include <boost/mpl/if.hpp>
    #include <boost/mpl/not.hpp>
    #include <boost/mpl/vector.hpp>
    
    namespace mpl = boost::mpl;
    
    template<typename Sequence, typename T>
    struct push_front;
    
    template<template<typename...> class Sequence, typename T, typename ... Args>
    struct push_front< Sequence<Args...>,T> {
      typedef Sequence<T, Args...> type;
    };
    
    template<template<typename...> class To, typename From> struct tuple_change;
    
    template<template<typename...> class To, template<typename...> class From, typename ... Args>
    struct tuple_change<To, From<Args...>>
    {
      typedef To<Args...> type;
    };
    
    template<typename Sequence, size_t N>
    struct at : std::tuple_element<N,Sequence> { };
    
    template<typename Sequence>
    struct empty;
    
    template<template<typename...> class Sequence, typename ... Args>
    struct empty<Sequence<Args...>> {
      typedef Sequence<> type;
    };
    
    template<
      size_t N,
      typename Sequence,
      template<typename> class Pred,
      typename ... Args >
    struct while_impl
    {
      typedef typename mpl::if_c<
        Pred<
            typename at<Sequence, sizeof...(Args) - N -1>::type
        >::value,
        typename push_front<
            typename while_impl<N-1, Sequence, Pred, Args...>::type, 
                typename at<Sequence,sizeof...(Args)-N-1>::type
        >::type,
        typename empty< Sequence > ::type
      >::type type;
    };
    
    template<
      typename Sequence,
      template<typename> class Pred,
      typename ... Args >
    struct while_impl<-1, Sequence, Pred, Args...>
    : empty<Sequence> {
    };
    
    
    template<
      typename Sequence,
      template<typename> class Pred>
    struct while_;
    
    template<
      template<typename...> class Sequence,
      template<typename> class Pred,
      typename ... Args >
    struct while_< Sequence<Args...>, Pred >
    {
      typedef typename while_impl<sizeof...(Args)-1, Sequence<Args...>, Pred, Args...>::type type;
    };
    
    template<typename T>
    struct not_na : mpl::not_< std::is_same<mpl_::na, T> >
    { };
    
    template<template<typename...> class To, typename From>
    struct to_boost;
    
    template<template<typename...> class To, typename...Args >
    struct to_boost<To, std::tuple<Args...> > :
      tuple_change< mpl::vector, std::tuple<Args...> >
    { };
    
    template< typename From >
    struct to_std;
    
    template<template<typename...> class From, typename...Args >
    struct to_std< From<Args...> > :
       while_<typename tuple_change< std::tuple, From<Args...> >::type, not_na>
    { };
    
    static_assert(
    std::is_same<
        mpl::vector< char, int, bool>,
        typename to_boost<mpl::vector, std::tuple<char, int, bool> >::type
      >::value,
    "tuple_change to boost failed");
    
    static_assert(
      std::is_same<
        std::tuple< char, int, bool>,
        typename to_std< mpl::vector<char, int, bool> >::type
      >::value,
    "tuple_change from boost failed");
    
    int main(){ return 0;}
    

    *tested with:
    boost_1_46_0 and g++-4.5 on MacOSx
    boost_1_45_0 and g++-4.5 on Ubuntu 10.10