No need to return a lambda
I don't see the need for returning a lambda which you then have to invoke. Why not pass the function as the first parameter, similar to std::apply
and std::invoke
? I would rewrite all_loop()
like so:
template <typename F, typename ...A>
constexpr void invoke_all(F f, A&& ...a)
noexcept(noexcept((f(std::forward<decltype(a)>(a)), ...)))
{
(f(std::forward<decltype(a)>(a)), ...);
}
And then you can use it like so:
invoke_all([](auto&& v){std::cout << v << '\n';}, 1, 2, 3, false, true, nullptr);
If you really need to have it as a lambda, the caller can still do that themselves:
auto curried = [](auto const f){invoke_all(f, 1, 2, 3, false, true, nullptr);};
curried([](auto&& v){std::cout << v << '\n';});
Prefer '\n'
over std::endl
Use '\n'
instead of std::endl
; the latter is equivalent to the former, but also forces the output to be flushed, which is normally not necessary and might impact performance.
Making it "pipeable"
I wanted to achieve something like pipe(1, 2, 3) | f;
You can do that as well, by creating a type that stores the values and overloads operator|
to take any function. For example:
template <typename... A>
class pipe
{
std::tuple<A...> a;
public:
pipe(A&&... a): a{a...} {}
auto operator|(auto&& f) {
std::apply([&](auto&&... a){(f(a), ...);}, a);
}
};
(I left all the decltype
s and std::forward
s as an excercise to the reader.) Then you can indeed write:
pipe(1, 2, 3, false, true, nullptr) | [](auto&& v) { std::cout << v << '\n'; };
But I would not use this, and rather stick to the idiomatic way of calling things in C++.