XPlatformer
XPlatformer

Reputation: 1218

From typelist to argument pack

I have a typelist of the form described here:

http://www.drdobbs.com/generic-programmingtypelists-and-applica/184403813

Each type has a duck-typed function (template/compile-time virtual) called get() which returns a simple type like this:

struct Float {
  float get() { return 7.0; }
};
struct Int {
  int get() { return 7; }
};
typedef typelist<Float, typelist<Int, null_typelist>> types;

I also have a function that takes a variadic number of simple type arguments, like this:

template<typename... Args>
foo(Args... args)
{
}

Now I need a way to call foo given types. I think there's a solution to this, via a tuple, but I'm really far from a solution that works... I hope you can help me here!

Upvotes: 1

Views: 1322

Answers (2)

Alastair Harrison
Alastair Harrison

Reputation: 1361

I think this can be done without using std::tuple. As others have mentioned, C++11 and onwards support typelists based on parameter packs, which are much easier to work with than the C++03 recursive typelists:

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

Assuming the C++03 typelists are part of an API that you can't change, the first thing is to convert the C++03 typelist to a C++11 typelist. That can be done with some empty function declarations acting as type functions:

// Concatenate two tlist types
template <typename... Ts, typename... Us>
static auto concat_impl(tlist<Ts...>, tlist<Us...>) -> tlist<Ts..., Us...>;

// Base case
static auto to_tlist_impl(null_typelist) -> tlist<>;

// Recursive case
template <typename Head, typename Tail>
static auto to_tlist_impl(typelist<Head, Tail>)
    -> decltype(concat_impl(tlist<Head>{}, to_tlist_impl(Tail{})));

// Alias template to make usage easier
template <typename Typelist>
using to_tlist = decltype(to_tlist_impl(Typelist{}));

Next, provide a helper function to take the parameter pack out of a tlist and pass it to the foo function. The original question did not specify how the types should be constructed, so here they are just default constructed as they are passed in to foo.

template <typename... Ts>
void call_foo(tlist<Ts...>) {
    foo(Ts{}...);
}

Finally, to call foo with a recursive typelist type just convert it to a tlist with the to_tlist type function:

    using list = typelist<Int, typelist<Float, typelist<String, null_typelist>>>;
    call_foo(to_tlist<list>{});

Godbolt example: https://godbolt.org/z/j8P55v7Kb

Upvotes: 0

ForEveR
ForEveR

Reputation: 55887

This code converts typelist to tuple and calls foo with simple types.

#include <tuple>
#include <iostream>

template<typename H, typename T>
struct typelist
{
    typedef H Head;
    typedef T Tail;
};

struct null_typelist {};


template<int... Indices>
struct indices {
    using next = indices<Indices..., sizeof...(Indices)>;
};

template<int Size>
struct build_indices {
    using type = typename build_indices<Size - 1>::type::next;
};

template<>
struct build_indices<0> {
    using type = indices<>;
};

template<typename T>
using Bare = typename std::remove_cv<typename std::remove_reference<T>::type>::type;

template<typename Tuple>
constexpr
typename build_indices<std::tuple_size<Bare<Tuple>>::value>::type
make_indices()
{ return {}; }

template<typename T, typename... Args>
struct tuple_push;

template<typename T, typename... Args>
struct tuple_push<T, std::tuple<Args...>>
{
    typedef std::tuple<Args..., T> type;
};

template<typename TL>
struct typelist_to_tuple;

template<typename H, typename T>
struct typelist_to_tuple<typelist<H, T>>
{
    typedef typename tuple_push<H, typename typelist_to_tuple<T>::type>::type type;
};

template<typename H>
struct typelist_to_tuple<typelist<H, null_typelist>>
{
    typedef std::tuple<H> type;
};

struct Float {
  float get() const { return 7.5; }
};
struct Int {
  int get() const { return 7; }
};

template<typename... Args>
void foo(const Args&... args)
{
}

template<typename T, typename... Args>
void foo(const T& current, const Args&... args)
{
    std::cout << current << std::endl;
    foo(args...);
}

template<typename Tuple, int... Indices>
void apply(const Tuple& tuple, indices<Indices...>)
{
    foo(std::get<Indices>(tuple).get()...);
}

template<typename Tuple>
void apply(const Tuple& tuple)
{
    apply(tuple, make_indices<Tuple>());
}

int main()
{
    typedef typelist<Int, typelist<Float, typelist<Int, null_typelist>>> list;
    typedef typelist_to_tuple<list>::type tuple;
    tuple t = std::make_tuple(Int(), Float(), Int());
    apply(t);
}

live example

Upvotes: 2

Related Questions