I would like to write a function that applies a function to each element of a parameter pack. The functions returns a std::tuple
with the results of each invocation.
However, if the applied function returns void
, I have to do something else, so I have a different overload for this case. But, almost all the ways I've found to expand the parameter pack do not work with void
expressions, so I had to resort to what you see below, which seems a weird trick.
template<typename F, typename ...Args>
requires requires { std::tuple{std::declval<F>(Args)...}; }
auto for_each(F f, Args ...args) {
return std::tuple{f(args)...};
}
template<typename F, typename ...Args>
auto for_each(F f, Args ...args)
[[maybe_unused]] int a[] = {(f(Members), 0)...};
}
Note that I have to declare a unused variable and mark it with the attribute. Which is the best way to obtain the expected result here?
This trick is the way to go pre-C++17, except that you need an extra , 0
in the array to support zero-length packs.
In C++17 and newer, use a fold expression: (f(args), ...);
.
Note that you forgot perfect forwarding. You should be doing F &&f, Args &&... args
, and then (f(std::forward<Args>(args)), ...);
, and similarly for the first function.
I also question the value of having such a function. I'd understand doing this to a tuple, but if you already have a pack, you can do this manually at the call site.