c++boostmetaprogrammingboost-mpl

Creating all template permutations with MPL


I have the following templated class structure

struct TraitA{};
struct TraitB{};

template<typename trait>
struct FunctionalityA{};

template<typename trait>
struct FunctionalityB{};

template<typename Func>
struct FuncUserA{};

template<typename Func>
struct FuncUserB{};

template<typename fuser>
struct Host{};

The Host class can now how have the following types.

typedef Host<FuncUserA<FunctionalityA<TraitA> > > Host1_t;
typedef Host<FuncUserA<FunctionalityA<TraitB> > > Host2_t;
typedef Host<FuncUserA<FunctionalityB<TraitA> > > Host3_t;
typedef Host<FuncUserA<FunctionalityB<TraitB> > > Host4_t;
typedef Host<FuncUserB<FunctionalityA<TraitA> > > Host5_t;
typedef Host<FuncUserB<FunctionalityA<TraitB> > > Host6_t;
typedef Host<FuncUserB<FunctionalityB<TraitA> > > Host7_t;
typedef Host<FuncUserB<FunctionalityB<TraitB> > > Host8_t;

Is there any way to create a type list with boost::mpl? At the moment I don't even have an Idea where to start. My Goal would be to have a function like this:

template<class T>
T* getHost()
{
  typedef boost::mpl::find<HostVector, T>::type MplIter;
  return new MplIter;
}

Is this possible with boost::mpl?


Solution

  • Ok here is some implementation. It is rather ad-hoc, one could obviously abstract it to take a sequence of sequence of lambda function, but I preferred keeping this one straight. Comments and tests are inside:

    #include <iostream>
    
    ////////////////////////////////////////////////////////////////////////////////
    // Base types to permute around - added soem display for tests purpose
    ////////////////////////////////////////////////////////////////////////////////
    struct TraitA { TraitA() { std::cout << "TA"; } };
    struct TraitB { TraitB() { std::cout << "TB"; } };
    
    template<typename Trait>
    struct FunctionalityA
    {
      FunctionalityA() { std::cout << "FunctionalityA<"; Trait(); std::cout << ">";}
    };
    
    template<typename Trait>
    struct FunctionalityB
    {
      FunctionalityB() { std::cout << "FunctionalityB<"; Trait(); std::cout << ">";}
    };
    
    template<typename Func>
    struct FuncUserA
    {
      FuncUserA() { std::cout << "FuncUserA<"; Func(); std::cout << ">";}
    };
    
    template<typename Func>
    struct FuncUserB
    {
      FuncUserB() { std::cout << "FuncUserB<"; Func(); std::cout << ">";}
    };
    
    template<typename Fuser> struct Host
    {
      Host() { std::cout << "Host<"; Fuser(); std::cout << ">\n";}
    };
    
    ////////////////////////////////////////////////////////////////////////////////
    // Step 1 : Make static list of potential options
    //
    // These lists has to be updated as new Trait, FuncUser and Functionality are
    // made.
    ////////////////////////////////////////////////////////////////////////////////
    #include <boost/mpl/vector.hpp>
    #include <boost/mpl/placeholders.hpp>
    
    typedef boost::mpl::vector< TraitA, TraitB >              traits_list;
    typedef boost::mpl::vector< FunctionalityA<boost::mpl::_>
                              , FunctionalityB<boost::mpl::_>
                              >                                functionalities_list;
    
    typedef boost::mpl::vector< FuncUserA<boost::mpl::_>
                              , FuncUserB<boost::mpl::_>
                              >                                fusers_list;
    
    ////////////////////////////////////////////////////////////////////////////////
    // Step 1 : Build the types
    //
    // We want every combination of Trait and Functionality. This is basically a
    // cartesian product of traits_list and functionalities_list which is done
    // usign nested fold
    ////////////////////////////////////////////////////////////////////////////////
    #include <boost/mpl/fold.hpp>
    #include <boost/mpl/copy.hpp>
    #include <boost/mpl/push_back.hpp>
    #include <boost/mpl/back_inserter.hpp>
    
    template<typename Fusers, typename Functionalities, typename Traits>
    struct build_combo
    {
      //////////////////////////////////////////////////////////////////////////////
      // Inner fold loop iterating over the traits
      //////////////////////////////////////////////////////////////////////////////
      template<typename FuserFunc>
      struct traits_loop
      {
        template<typename T>
        struct fuse : boost::mpl::apply<FuserFunc,T> {};
    
        typedef typename
        boost::mpl::fold< Traits
                        , boost::mpl::vector<>
                        , boost::mpl::push_back < boost::mpl::_1
                                                , fuse<boost::mpl::_2>
                                                >
                        >::type type;
      };
    
      //////////////////////////////////////////////////////////////////////////////
      // Inner fold loop iterating over the functionnality/traits
      //////////////////////////////////////////////////////////////////////////////
      template<typename Fuser>
      struct func_traits_loop
      {
        template<typename T>
        struct fuse : boost::mpl::apply<Fuser,T> {};
    
        typedef typename
        boost::mpl::fold< Functionalities
                        , boost::mpl::vector<>
                        , boost::mpl::copy< traits_loop< fuse<boost::mpl::_2> >
                                          , boost::mpl::back_inserter<boost::mpl::_1>
                                          >
                        >::type type;
      };
    
      //////////////////////////////////////////////////////////////////////////////
      // fold loop iterating over the Fuser x {Functionality,Traits}
      // For each Fuser, copy its vector of applications to the others
      //////////////////////////////////////////////////////////////////////////////
      typedef typename
      boost::mpl::fold< Fusers
                      , boost::mpl::vector<>
                      , boost::mpl::copy< func_traits_loop<boost::mpl::_2>
                                        , boost::mpl::back_inserter<boost::mpl::_1>
                                        >
                      >::type type;
    };
    
    ////////////////////////////////////////////////////////////////////////////////
    // Now the get_host meta-function
    ////////////////////////////////////////////////////////////////////////////////
    #include <boost/mpl/at.hpp>
    
    template<int N>
    struct get_host
    {
      typedef build_combo < fusers_list
                          , functionalities_list
                          , traits_list
                          >::type                     types;
      typedef typename boost::mpl::at_c<types,N>::type hosted;
      typedef Host<hosted> type;
    };
    
    ////////////////////////////////////////////////////////////////////////////////
    // Some tests
    ////////////////////////////////////////////////////////////////////////////////
    
    int main()
    {
      get_host<1>::type x1;
      get_host<2>::type x2;
      get_host<3>::type x3;
      get_host<4>::type x4;
      get_host<5>::type x5;
      get_host<6>::type x6;
      get_host<7>::type x7;
    }
    

    The expected output should be :

    Host<FuncUserA<FunctionalityA<TB>>>
    Host<FuncUserA<FunctionalityB<TA>>>
    Host<FuncUserA<FunctionalityB<TB>>>
    Host<FuncUserB<FunctionalityA<TA>>>
    Host<FuncUserB<FunctionalityA<TB>>>
    Host<FuncUserB<FunctionalityB<TA>>>
    Host<FuncUserB<FunctionalityB<TB>>>