完美转发一份std::tuple

Perferct forward a copied std::tuple

我需要一点帮助。我需要以特定方式完善转发元组。想象一下

template <typename F, typename... Args>
auto package_task(F&& func, Args&&... args) -> std::function<void()>
{
    //for the purposes of this example imagine capture to be std::move and
    //to be inplace in the lambdas' capture.
    auto callable = capture(std::forward<F>(func));
    auto params = capture(std::make_tuple(std::forward<Args>(args)...));

    return [callable , params]() mutable { std::apply(callable, params); };
}

打包的任务稍后将在不同的线程上执行,但是当我调用 apply 时,我需要 "callable" 使其参数从元组扩展并转发,就像它们在 package_task 函数。我不能使用 forward_as_tuple 因为我是 copying/moving 参数和稍后要执行的可调用对象。我需要像

这样的东西
template <typename F, typename... Args>
auto package_task(F&& func, Args&&... args) -> std::function<void()>
{
    //for the purposes of this example image capture to be std::move and
    //to be inplace in the lambdas' capture.
    auto callable = capture(std::forward<F>(func));
    auto params = capture(std::make_tuple(std::forward<Args>(args)...));

    return [callable , params]() mutable { std::apply_but_expand_as<Args&&…>(callable, params); };
}

如有任何想法,我们将不胜感激。

如果您正在尝试制作一个可转发其参数的一次性调用,您可以使用 C++17 或更早版本做的最好的事情是:

template <typename F, typename... Args>
auto package_task(F&& func, Args&&... args) -> std::function<void()>
{
    return [func = std::forward<F>(func),
            args_tuple = std::make_tuple(std::forward<Args>(args)...)]
           () mutable
    {
        return std::apply([](auto&&... args){
            return std::invoke(
                std::forward<F>(func),
                std::forward<Args>(args)...
                );
        }, args_tuple);
    };
}

也就是说,您 forwardArgs 放入元组,apply 元组,然后 forward 它们退出。


在 C++20 中,由于 P0780,这可以简化为:

template <typename F, typename... Args>
auto package_task(F&& func, Args&&... args) -> std::function<void()>
{
    return [func = std::forward<F>(func),
            ...args = std::forward<Args>(args)] () mutable
    {
        return std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
    };
}