c++templatesvariadic-templatestype-traitspack-expansion

Why does pack expansion fail in my std::tuple transformation type trait?


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.


Solution

  • 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() {}
    

    Demo