I'm trying to build the compile-time "tupled" version of std::transform
. This type traits should take in a std::tuple
, a unary type trait that "returns" a type (such as std::remove_pointer
) and should produce a std::tuple
whose types are the result of applying the type trait to the corresponding type of the input std::tuple
For example, my_tuple_trasform<std::tuple<int*, float&, double*>, std::remove_pointer>::type
should be equivalent to std::tuple<int, float&, double>
.
I could easily write a solution recursively, but I was trying to implement an "iterative" solution through an expansion pack, and I can't figure out what I'm getting wrong.
Here's my code:
template <typename Tuple, template<typename> typename TraitPredicate>
struct my_tuple_trasform;
template <template<typename> typename TraitPredicate, typename... Ts>
struct my_tuple_trasform<std::tuple<Ts...>, TraitPredicate>
{
using type = std::tuple<(typename TraitPredicate<Ts>::type)...>;
};
The compiler produces an unhelpful error, where it points out that the expression
(typename TraitPredicate<Ts>::type)
is not recognized as a parameter pack and it also seems to think that the whole thing, ellipsis included, is just the first type of the std::tuple
.
It was close: you have to skip the parenthesis in using type = std::tuple<(typename TraitPredicate<Ts>::type)...>;
#include <tuple>
template <typename Tuple, template<typename> typename TraitPredicate>
struct my_tuple_trasform;
template <template<typename> typename TraitPredicate, typename... Ts>
struct my_tuple_trasform<std::tuple<Ts...>, TraitPredicate>
{
using type = std::tuple<typename TraitPredicate<Ts>::type...>;
};
using T1 = std::tuple<int*, float&, double*>;
using T2 = my_tuple_trasform<T1, std::remove_pointer>::type;
static_assert (std::is_same_v<T2, std::tuple<int, float&, double>>);
int main() {}