I\'d like to create the cross product of a list of types using variadic templates.
Here\'s what I have so far:
#include
#include <
A nice clean version I think:
cross_product.cpp:
#include "type_printer.hpp"
#include
template struct type_list {};
template struct pair {};
// Concatenation
template struct concat;
template
struct concat, type_list>
{
typedef type_list type;
};
// Cross Product
template struct cross_product;
// Partially specialise the empty case for the first type_list.
template
struct cross_product, type_list> {
typedef type_list<> type;
};
// The general case for two type_lists. Process:
// 1. Expand out the head of the first type_list with the full second type_list.
// 2. Recurse the tail of the first type_list.
// 3. Concatenate the two type_lists.
template
struct cross_product, type_list> {
typedef typename concat<
type_list...>,
typename cross_product, type_list>::type
>::type type;
};
struct A {};
struct B {};
struct C {};
struct D {};
struct E {};
struct F {};
template
void test()
{
std::cout << print_type() << " \u2a2f " << print_type() << " = "
<< print_type::type>() << std::endl;
}
int main()
{
std::cout << "Cartesian product of type lists\n";
test, type_list<>>();
test, type_list>();
test, type_list>();
test, type_list<>>();
test, type_list>();
test, type_list>();
test, type_list>();
test, type_list>();
test, type_list>();
return 0;
}
type_printer.hpp:
#ifndef TYPE_PRINTER_HPP
#define TYPE_PRINTER_HPP
#include "detail/type_printer_detail.hpp"
template
std::string print_type()
{
return detail::type_printer()();
}
#endif
detail/type_printer_detail.hpp:
#ifndef DETAIL__TYPE_PRINTER_DETAIL_HPP
#define DETAIL__TYPE_PRINTER_DETAIL_HPP
#include
#include
#include
template struct type_list;
template struct pair;
namespace detail {
// print scalar types
template
struct type_printer {
std::string operator()() const {
int s;
return abi::__cxa_demangle(typeid(T).name(), 0, 0, &s);
}
};
// print pair types
template
struct type_printer> {
std::string operator()() const {
return "(" + type_printer()() + "," + type_printer()() + ")";
}
};
// print type_list
template <>
struct type_printer> {
std::string operator()() const {
return "\u2205";
}
};
template
struct type_printer> {
std::string operator()() const {
return "{" + type_printer()() + "}";
}
std::string operator()(const std::string& sep) const {
return sep + type_printer()();
}
};
template
struct type_printer> {
std::string operator()() const {
return "{" + type_printer()() + type_printer>()(std::string(", ")) + "}";
}
std::string operator()(const std::string& sep) const {
return sep + type_printer()() + type_printer>()(sep);
}
};
}
#endif
Run:
g++ -std=c++0x cross_product.cpp && ./a.out
Output:
Cartesian product of type lists
∅ ⨯ ∅ = ∅
∅ ⨯ {A} = ∅
∅ ⨯ {A, B} = ∅
{A, B} ⨯ ∅ = ∅
{A} ⨯ {B} = {(A,B)}
{A} ⨯ {B, C, D} = {(A,B), (A,C), (A,D)}
{A, B} ⨯ {B, C, D} = {(A,B), (A,C), (A,D), (B,B), (B,C), (B,D)}
{A, B, C} ⨯ {D} = {(A,D), (B,D), (C,D)}
{A, B, C} ⨯ {D, E, F} = {(A,D), (A,E), (A,F), (B,D), (B,E), (B,F), (C,D), (C,E), (C,F)}
(I noticed on Windows using Chrome that the cross product unicode character is not coming out well. Sorry, I don't know how to fix that.)