使用std::函数包装函数对象
Using an std::function for wrapping a function object
有人能帮我理解为什么下面的代码会导致错误吗?
class A
{
public:
float& operator()()
{
return _f;
}
private:
float _f = 1;
} a;
auto& foo()
{
std::function<float()> func = a;
return func();
}
int main()
{
std::cout << foo() << std::endl;
}
错误:
error: non-const lvalue reference to type 'float' cannot bind to a temporary of type 'float'
return func();
^~~~~~
1 error generated.
这里,在operator()
中,我返回对_f
的引用,因此,我认为func()
不是临时的。如果有人帮我理解就太好了。
问题不在于std::function
的使用,而是您试图从func()
返回临时float
作为引用。这不会起作用,因为一旦语句结束,对象就会不存在。
如果将auto& foo()
更改为auto foo()
,它应该可以工作。
我想您已经明白,一旦变量超出范围,返回对局部变量的引用是无效的。不过,您似乎缺少的是std::function<float()> func = a;
实际上从a
创建了一个本地std::function
。它没有以任何方式指向a
,func
有自己的A
。这意味着调用func();
实际上并没有调用a.operator()
,而是调用func
的A
。然后我们回到局部变量,返回一个引用是邪恶的部分。
为了使其编译,您可以将模板签名更改为float&()
,但它仍然是未定义的行为。
修复方法是将返回类型改为副本(auto
(,删除引用。
对于std::function<float()> func
,您将func
声明为返回float
的函子,而不是float&
。正如错误消息所说,func()
返回的临时float
不能绑定到非常量左值引用。
上面的声明与正在包装的A::operator()
的签名不匹配。但请注意,如果将类型更改为std::function<float&()> func
以匹配A::operator()
的签名,则可能会解决编译错误,但随后我们将返回绑定到局部变量的引用,从而导致UB。
请注意,对于std::function<float()> func = a;
,std::函数是用a
的副本初始化的。然后,func()
将返回一个绑定到func
中封装的A
成员的引用,这是一个局部变量。当退出函数foo
时,引用将挂起。
如何修复它取决于您的设计,将auto& foo()
更改为auto foo()
,即通过复制传递返回值可以避免UB。
在阅读了上面的精彩答案后,我试图给出一些不同的想法。
我想OP真的想返回某个对象的float&
(在OP的例子中是a
(。
因此,如果OP希望foo
返回auto&
(应该是float&
(,则应如下所示,请注意std::bind
部分:
namespace T1
{
class A
{
public:
float& operator()()
{
std::cout << "a add = " << this << std::endl;
return _f;
}
float getF() { return _f; }
private:
float _f = 1;
} a;
auto& foo()
{
std::function<float&()> func = std::bind(&A::operator(), &a);
return func();
}
} // end of namespace T1
int main()
{
std::cout << "global a add = " << &(T1::a) << std::endl; // check a's address
float& f = T1::foo(); // note that `a`'s address is the same
std::cout << f << std::endl; // still 1
f = 777;
std::cout << f << std::endl; // now 777
std::cout << T1::a.getF() << std::endl; // it's 777
return 0;
}
- 如何使用单独文件中的派生类访问友元函数对象
- 当使用透明的std函数对象时,我们还需要写空的尖括号吗
- 有没有办法将重载的类函数绑定到函数对象?
- 将指针传递到成员的指针,从模板参数包到函数对象
- 如何在类模板的成员函数中正确调用函数对象?正在生成 Visual Studio 编译器错误 C2440
- 隐式转换为比较函数对象(函子)用于 std::sort 而不是 std::map?
- C++使用函数对象的线程,如何调用多个析构函数而不是构造函数?
- 如何通过接口将函子分配给函数对象
- 对std::函数对象的调用不匹配,该对象是指向成员函数的指针
- 指向std::invoke中成员函数对象的指针
- 如何成功地将函数对象(或lambda)传递给trackbar回调的第二个参数(void*)
- "std::function"的简单版本:函数对象的生存期?
- C++ 将函数对象作为左值和/或右值传递
- SFINAE 用于具有默认参数的函数对象
- 构造函数对象赋值是否泄漏内存
- 如何发送通过绑定到函数/方法创建的函数对象?
- std::for_each 与函数对象
- 将函数对象传递给 std::function
- 访问执行策略for_each函数对象中的迭代器
- 通过C++函数对象类访问参数