Reputation: 1218
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
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
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);
}
Upvotes: 2