Reputation: 2271
Can someone help me 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 understand.
Upvotes: 5
Views: 774
Reputation: 3035
After reading the great answers above, I tried to give some different thoughts.
I guess OP really wants to return a float&
of a certain object (which is a
in OP's example).
So if OP wants foo
to return auto&
(which should be a float&
), then it should be as the following, please note the std::bind
part:
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;
}
Upvotes: 1
Reputation: 172864
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.
Upvotes: 1
Reputation: 36463
I think you understand that returning a reference to a local variable isn't valid once the variable goes out of scope. What you seem to be missing though is that std::function<float()> func = a;
actually creates a local std::function
from a
. It doesn't point to a
in any way, func
has it's own A
. Which means that calling func();
doesn't actually invoke a.operator()
but rather the A
of func
. Then we get back to the local variable returning a reference is evil part.
To make it compile, you can change your template signature to float&()
but it's still undefined behaviour.
A fix would be to change the return type to a copy instead (to auto
), removing the reference.
Upvotes: 3
Reputation: 25573
The problem isn't the use of std::function
, its that you're trying to return the temporary float
from func()
as a reference.
This won't work since the object would cease to exist as soon as the statement ends.
If you change auto& foo()
to auto foo()
it should work.
Upvotes: 5