properly forward a parameter pack in a lambda without discarding qualifiers

Viewed 104

I am trying to store lambda functions in a queue to execute them later. In order to do that, i am trying to hide the parameter pack in a lambda without losing scope so I can still access the passed arguments in an upper scope. Sadly I cannot compile this since the parameter pack does not match the const qualifier. I hope it is easier to understand what I am trying to accomplish by looking at the following code. (I am using c++17, not c++20). I think I misunderstand how to properly forward the variadic parameter pack since as I do it right now, the binding reference to const will discard qualifiers.

It is sadly not an option to expect the parameters in the functional lambda to be const.

std::queue<std::function<void()>> fcts;

template<typename F >
auto push_fct(F &task) -> void {
    // Do things
    fcts.push(std::move(std::function<void()>(task)));
}

template<typename F, typename... A>
auto push_fct(F& task , A&... args) -> void {
    push_fct( [task, args...] { task(args...);});
}

auto main() -> int {

    auto functional = [&](class_a & a, class_b & b) {
        a.memberFct();
        b.memberFunction(123);
    }

    class_a instance_a;
    class_b instance_b;

    push_fct(functional, instance_a, instance_b);


    return 0;
}
1 Answers

What happens is, here [task, args...] the references are lost; task, args... are captured by value, which, in a non-mutable lambda additionally become const, which subsequently can't bind to non-const references in the call to [&](class_a & a, class_b & b).

You can capture the references by reference. Don't worry about their lifetime - the references are collapsed, and the original ones will be captured (source).

template<typename F>
auto push_fct(F&& task) -> void {
    // Do things
    fcts.emplace(std::forward<F>(task));
}

template<typename F, typename... A>
auto push_fct(F& task, A&... args) -> void {
    push_fct([&task, &args...]{ task(args...); });
}
Related