Welcome to 16892 Developer Community-Open, Learning,Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

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?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
576 views
Welcome To Ask or Share your Answers For Others

1 Answer

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)...);
            });
        });
    };
};

Demo

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to 16892 Developer Community-Open, Learning and Share
...