I think you can do this quite simply without C ++ 14. I am going to assume a few things about how your Tuple
is created, namely that these two ctors exist:
Tuple(First, Rest... ); // (1) Tuple(First, const Tuple<Rest...>& ); // (2)
We need one type trait: with the help of the function with which we are transformed, we need to know what types it produces:
template <typename T, typename F> using apply_t = decltype(std::declval<F>()(std::declval<T>()));
(God I love C ++ 11)
With this, we can easily determine the return type and simply call the function recursively:
template <typename First, typename... Rest> struct Tuple { template <typename F> Tuple<apply_t<First, F>, apply_t<Rest, F>...> Transform(F func) { return {func(first), rest.Transform(func)};
(Depending on how you wrote your Tuple
, you may or may not need a base case for a trivial conversion that just returns a Tuple<>
or a base case that just returns Tuple<apply_t<First, F>>
. Anyway , not a big deal).
And you donβt even need to specialize Tuple
at all. You just need to go to the desired functors. For instance:
struct Zero { template <typename T> int operator()(T ) { return 0; } }; struct Incr { template <typename T> T operator()(T x) { return x + 1; } }; Tuple<int, double, char> tup(1, 2.0, 'c'); auto z = tup.Transform(Zero{});
Here's a complete code example that registers all types too. Of course, with C ++ 14 we can do these inline:
auto i2 = tup.Transfom([](auto x) -> decltype(x) {return x+1; });