I want to chain/compose multiple lambdas to a new lambda. When calling the new lambda with parameters it should call the original lambdas with these parameters. This lambda chaining does work well when the parameters are just copied but when I want to modify them perfect forwarding does not work:
#include <boost/hana.hpp>
#include <cassert>
constexpr auto chain_lambdas = [](auto... lambdas) {
constexpr auto lambdasTpl = boost::hana::make_basic_tuple(lambdas...);
return [lambdas(lambdasTpl)](auto&&... args) {
auto argsTpl = boost::hana::make_basic_tuple(std::forward<decltype(args)>(args)...);
boost::hana::for_each(lambdas, [args(argsTpl)](auto lambda) mutable {
boost::hana::unpack(std::move(args), [lambda(lambda)](auto&&... args) {
lambda(std::forward<decltype(args)>(args)...);
});
});
};
};
auto main() -> int
{
auto lambda1 = [](bool& called){
called = true;
};
auto lambda2 = [](bool& called){
called = true;
};
bool called = false;
chain_lambdas(lambda1, lambda2)(called);
assert(called == true);
return 0;
}
Code at the compiler explorer. Does perfect forwarding even work for this use case?
auto argsTpl = boost::hana::make_basic_tuple(std::forward<decltype(args)>(args)...);
does copy (move) of arguments, so you only mutate the copy.
You need std::forward_as_tuple
equivalent for boost:
constexpr auto chain_lambdas = [](auto... lambdas) {
constexpr auto lambdasTpl = boost::hana::make_basic_tuple(lambdas...);
return [lambdas(lambdasTpl)](auto&&... args) {
auto argsTpl = boost::hana::basic_tuple<decltype(args)...>(std::forward<decltype(args)>(args)...);
boost::hana::for_each(lambdas, [args(argsTpl)](auto lambda) mutable {
boost::hana::unpack(args, [lambda(lambda)](auto&&... args) {
lambda(std::forward<decltype(args)>(args)...);
});
});
};
};
On my side, only with std (C++17), you might do:
constexpr auto chain_lambdas = [](auto... lambdas) {
return [=](auto&&... args) {
return std::apply([&](auto... f){ (f(args...), ...); }, std::tie(lambdas...));
};
};
Demo.
I drop std::forward
for args
as calling function with moved object might be undesirable, but you can enable it if wanted.