Home > front end >  How to call a templated function for each type in a tuple (acting as type list) with tuple b as argu
How to call a templated function for each type in a tuple (acting as type list) with tuple b as argu

Time:05-09

How to call a template function for each type in a typelist with arguments (e.g. another tuple)?

Given is a typelist std::tuple<T1, T2, T3, ...> and a std::tuple containing data.

template <typename T>
void doSomething (const auto& arg) {
    std::cout << __PRETTY_FUNCTION__ << '\n';
}

template <typename T> struct w {T v; w(T _v) : v{_v} {}};

int main () {
    using types = std::tuple<int, char, float, double, w<int>, w<float>>; // used as type list
    constexpr auto data = std::make_tuple(1, 2, 3.0, 4.0f, w(5.0));
    // call doSomething<T>(data) for each type in types
    // like
    // someFunctor<types>(doSomething, data);
}

My current idea is a functor like appreach that receives the typelist to extract nexted types and std::tuple<Ts> having an operator () to call doSomething<T>(args) for each of Ts.

template<template<typename...> typename TL, typename... Ts>
struct someFunctor {
    template<typename... Args>
    static constexpr void operator() (Args&&... args) {
        (doSomething<Ts>(std::forward<Args>(args)...), ...);
    }
};

Not sure if that's the smartest approach. Brain fog blocked me so far to get it work.

CodePudding user response:

Use template partial specialization to extract the type of typelist, then use fold-expression to invoke doSomething with different template parameters

template<typename Tuple>
struct someFunctor;

template<typename... Args>
struct someFunctor<std::tuple<Args...>> {
  template<class T>
  constexpr void operator()(T&& x) {
    (doSomething<Args>(std::forward<T>(x)), ...);
  }
};

Demo

using types = std::tuple<int, char, float, double, w<int>, w<float>>;
constexpr auto data = std::make_tuple(1, 2, 3.0, 4.0f, w(5.0f));
someFunctor<types>()(data);

CodePudding user response:

Here's a short piece of code to do it:

using types = std::tuple<int, char, float, double, w<int>, w<float>>;
constexpr auto data = std::make_tuple(1, 2, 3.0, 4.0f, w(5.0));
[&]<template<typename...> class TL, typename... Ts>(TL<Ts...>*) {
    // Now have a parameter pack of `Ts`
    (doSomething<Ts>(data), ...);
}((types*) nullptr); 

And turned into a reusable function, you can do something like:

template<typename types, typename Functor, typename... Args>
constexpr void mapTypeList(Functor&& f, Args&&... args) {
    [&]<template<typename...> class TL, typename... Ts>(TL<Ts...>*) {
        ((void) f.template operator()<Ts>(std::forward<Args>(args)...), ...);
    }(static_cast<types*>(nullptr));
}


// You need to wrap `doSomething` in a lambda
mapTypeList<types>([]<typename T>(const auto& data) { doSomething<T>(data); }, data);
// or maybe capturing data:
mapTypeList<types>([&]<typename T>() { doSomething<T>(data); });

Example usage: https://godbolt.org/z/53x44bGvK

  • Related