std :: function是否支持完美转发?

rub*_*ict 7 c++ templates

是否std::function支持完美的论证转发?我决定测试一下:

struct Widget
{
    void operator()(int const&)
    {
        std::cout << "lvalue";
    }

    void operator()(int&&)
    {
        std::cout << "rvalue";
    }
};

std::function<void(int)> f{Widget()};
int x = 5;
f(x);
Run Code Online (Sandbox Code Playgroud)

猜猜哪个operator()被调用 - 采用右值参考的那个.它似乎是设计的.这种行为背后的理由是什么?

Bar*_*rry 10

是的,不是.是的,参数被转发.但是,不是,根据您在调用时提供的参数来完成重载解析 - 它是基于模板参数完成的std::function.

std::function<void(int)>意味着你有一个带有a的callable int,它隐含的是一个intrvalue.Widget使用rvalue类型调用会int优先于int&&重载过int const&载,这就是为什么选择该过载的原因.function一旦你选择了你想要的东西,你调用实际对象并不重要void(int)- 这是首选的重载.

实际的调用操作符的行为就像:

struct widget_function {
    void operator()(int arg) const {
//  ~~~~~           ~~~~
        w_(std::forward<int>(arg));
//                      ~~~
    }

    Widget w_;
};
Run Code Online (Sandbox Code Playgroud)

带下划线的部分来自您提供的签名std::function.你可以看到两者f(x)f(5)最终调用相同operator()Widget.


简而言之,std::function<Sig>类型擦除满足的单个过载Sig.它不会键入擦除整个过载集.你要求void(int),所以你void(int)只得到void(int).

  • @rubix_addict - 不是一般的.`std :: function`的意思是当你创建`std :: function`对象时,你定义它的接口.然后,您可以使用**任何**可调用对象填充它,该对象可以从`std :: function`函数调用运算符调用.你的`Widget`对象可以使用; 一个函数的原型是`double f(double);`.并且您可以随时替换可调用对象.但是您无法动态更改该运算符的签名,因此参数类型和返回类型不能依赖于您放入`std :: function`对象的可调用对象. (3认同)