通用引用不能接收函数对象是为什么?

问题遇到的现象和发生背景

学习通用引用的时候,遇到一个奇怪的问题,定义的函数对象,不能被通用引用接收,但用auto自动推导的却可以。

问题相关代码,请勿粘贴截图
#include <iostream>
#include <functional>

using namespace std;


template<typename Callback>
class Test{
public:
    Test(Callback &&cb) {

    }
};

int main() {
    function<void(int)>func1 = [] (int a){ return a; };
    auto func2 = [] (int a){ return a; };
    auto test1 = Test<function<void(int)>>(func1); //报错
    auto test2 = Test<function<void(int)>>(func2); //没问题
    return 0;
}

运行结果及报错内容

报错结果提示:
error: cannot bind rvalue reference of type ‘std::function<void(int)>&&’ to lvalue of type ‘std::function<void(int)>’

我的解答思路和尝试过的方法

意思是把func1当作了左值,但通用引用却没有特化出左值引用版本,而是只有右值引用版本,导致不能匹配。
把func1改成move(func1)后果然好了。

我想要达到的结果

请问这个是为什么呢?而且func2就没问题,感觉很奇怪

你的代码有问题,类的构造函数参数要求的是一个右值引用,而你给的是一个左值,所以出错,改一下

#include <iostream>
#include <functional>

using namespace std;


template<typename Callback>
class Test {
public:
    Test(Callback&& cb) {

    }
};

int main() {
    function<void(int)>func1 = [](int a) { return a; };
    auto func2 = [](int a) { return a; };
    auto test1 = Test<function<void(int)>>(std::move(func1)); //报错
    auto test2 = Test<function<void(int)>>(func2); //没问题
    return 0;
}


因为你的func1的返回值写的是void,但是{}中retuan a是返回的int类型,不匹配。

img

改成下面的就可以了:(只修改了func1那一行)

#include <iostream>
#include <functional>

using namespace std;


template<typename Callback>
class Test {
public:
    Test(Callback&& cb) {

    }
};

int main() {
    function<int (int)>func1 = [](int a) { return a; };  // 修改  把void改成int就可以了
    auto func2 = [](int a) { return a; };
    auto test1 = Test<function<void(int)>>(func1); //报错
    auto test2 = Test<function<void(int)>>(func2); //没问题
    return 0;
}


还是自己搞明白了,这里的Callback&& cb被认为是右值引用,所以只能绑定右值,然后类型不匹配的时候反而对,是由于类型不匹配,编译器会默认添加static_cast<>,这样就产生了一个临时对象,这个临时对象是右值,所以就编译通过了