abraham_hilbert abraham_hilbert - 1 month ago 9
C++ Question

Using an std::function for wrapping a function object

can someone help to understand why the following code causes an error:

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:

error: non-const lvalue reference to type 'float' cannot bind to a temporary of type 'float'
return func();
^~~~~~
1 error generated.


Here, in
operator()
, I return a reference to
_f
and consequently, I thought
func()
is not a temporary.
It would be great if someone helps me to understand.

Many thanks in advance.

Answer

For std::function<float()> func, you're declaring func as a functor returning a float, not a float&. As the error message said, the temporary float returned by func() can't be bound to non-const lvalue reference.

The above declaration doesn't match the signature of A::operator() which being wrapped. But note that if change the type to std::function<float&()> func to match the signature of A::operator(), the compile error could be sovled, but then we'll return a reference bound to local variable, which leads to UB.

Note that for std::function<float()> func = a;, std::function is initialized with a copy of a. Then func() will return a reference bound to member of A wrapped in func, which is a local variable. And the reference will dangle when get out of function foo.

How to fix it depends on your design, change auto& foo() to auto foo(), i.e. passing the return value by copy would avoid UB here.

Comments