通用参考和本地课程

Sta*_*ked 3 c++ forwarding forward perfect-forwarding forwarding-reference

在我的下面的代码中,我有一个接受"通用引用"(F&&)的函数.该函数还有一个内部类,它接受F&&构造函数中的对象.是F&&仍然在这一点上通用的参考?即F仍然被认为是推断类型?

换句话说,我应该使用std::forward<F>std::move在构造函数初始化列表中?

#include "tbb/task.h"
#include <iostream>
#include <future>

template<class F>
auto Async(F&& f) -> std::future<decltype(f())>
{
    typedef decltype(f()) result_type;

    struct Task : tbb::task
    {
        Task(F&& f) : f_(std::forward<F>(f)) {} // is forward correct here?

        virtual tbb::task* execute()
        {
            f_();
            return nullptr;
        }

        std::packaged_task<result_type()> f_;
    };

    auto task = new (tbb::task::allocate_root()) Task(std::forward<F>(f));
    tbb::task::enqueue(*task);
    return task->f_.get_future();
}


int main()
{
    Async([]{ std::cout << "Hi" << std::endl; }).get();
}
Run Code Online (Sandbox Code Playgroud)

现场演示.

Jon*_*ely 6

F&&仍然在这一点上通用的参考?即F仍然被认为是推断类型?

这种混乱是为什么我不喜欢通用引用一词...... 没有这样的事情.

我更喜欢用左值引用和右值引用来理解代码,以及参考规则折叠和模板参数推导的规则.

当使用左值类型调用函数时L,参数F将被推导为L&,并且参考折叠规则F&&就是L&.在Task构造函数中没有任何更改,F&&仍然L&是构造函数采用绑定到传递给的左值的左值引用,Async因此您不想移动它,并且forward是合适的,因为它保留了值类别,将左值转发为左值.(从左值移动会让调用者感到惊讶Async,他们不会期望左值可以无声地移动.)

当调用该函数时用类型的一个rvalue R参数F将被推导出R,因此F&&R&&.在Task构造函数中没有任何改变,F&&仍然R&&是构造函数采用绑定到传递给它的rvalue的rvalue引用,Async因此你可以移动它,但forward也是合适的,因为它保留了值类别,将rvalue转发为rvalue.

在上周的CppCon上,Herb Sutter宣布"通用参考"的首选术语现在转发参考,因为它更好地描述了它们的用途.