Search code examples
c++c++11variadic-templates

How to create the Cartesian product of a type list?


I'd like to create the cross product of a list of types using variadic templates.

Here's what I have so far:

#include <iostream>
#include <typeinfo>
#include <cxxabi.h>

template<typename...> struct type_list {};

template<typename T1, typename T2> struct type_pair {};

template<typename T, typename... Rest>
  struct row
{
  typedef type_list<type_pair<T,Rest>...> type;
};

template<typename... T>
  struct cross_product
{
  typedef type_list<typename row<T,T...>::type...> type;
};

int main()
{
  int s;
  typedef cross_product<int, float, short>::type result;
  std::cout << abi::__cxa_demangle(typeid(result).name(), 0, 0, &s) << std::endl;

  return 0;
}

This program outputs:

$ g++ -std=c++0x cross_product.cpp ; ./a.out 
type_list<type_list<type_pair<int, int>, type_pair<int, float>, type_pair<int, short> >, type_list<type_pair<float, int>, type_pair<float, float>, type_pair<float, short> >, type_list<type_pair<short, int>, type_pair<short, float>, type_pair<short, short> > >

But I'd like it to output:

type_list<type_pair<int,int>, type_pair<int,float>, type_pair<int,short>, type_pair<float,int>,...>

That is, without the nested type_lists.

Is there a direct way to do this without the row helper, or should the solution "unwrap" the nested type_lists somehow?


Solution

  • Somehow my brain is fried: I think I'm using more code than is needed but, at least, it has the desired results (although I didn't fix the memory leak):

    #include <iostream>
    #include <typeinfo>
    #include <cxxabi.h>
    
    template<typename...> struct type_list {};
    
    template<typename T1, typename T2> struct type_pair {};
    
    template<typename T, typename... Rest>
      struct row
    {
      typedef type_list<type_pair<T,Rest>...> type;
    };
    
    template <typename... T> struct concat;
    template <typename... S, typename... T>
    struct concat<type_list<S...>, type_list<T...>>
    {
        typedef type_list<S..., T...> type;
    };
    
    template <typename... T>
    struct expand
    {
        typedef type_list<T...> type;
    };
    template <> struct expand<> { typedef type_list<> type; };
    template <typename... T, typename... L>
    struct expand<type_list<T...>, L...>
    {
        typedef typename concat<typename expand<T...>::type, typename expand<L...>::type>::type type;
    };
    
    template<typename... T>
      struct cross_product
    {
        typedef typename expand<type_list<typename row<T,T...>::type...>>::type type;
    
    };
    
    int main()
    {
      int s;
      typedef cross_product<int, float, short>::type result;
      std::cout << abi::__cxa_demangle(typeid(result).name(), 0, 0, &s) << std::endl;
    
      return 0;
    }