While reading this explanation on lvalues and rvalues, these lines of code stuck out to me:
int& foo();
foo() = 42; // OK, foo() is an lvalue
I tried it in g++, but the compiler says "undefined reference to foo()". If I add
int foo()
{
return 2;
}
int main()
{
int& foo();
foo() = 42;
}
It compiles fine, but running it gives a segmentation fault. Just the line
int& foo();
by itself both compiles and runs without any problems.
What does this code mean? How can you assign a value to a function call, and why is it not an rvalue?
int & foo();
means thatfoo()
returns a reference to a variable.Consider this code:
This code prints:
$ ./a.out k=5
Because
foo()
returns a reference to the global variablek
.In your revised code, you are casting the returned value to a reference, which is then invalid.
The explanation is assuming that there is some reasonable implementation for
foo
which returns an lvalue reference to a validint
.Such an implementation might be:
Now, since
foo
returns an lvalue reference, we can assign something to the return value, like so:This will update the global
a
with the value42
, which we can check by accessing the variable directly or callingfoo
again:All the other answers declare a static inside the function. I think that might confuse you, so take a look at this:
Because
highest()
returns a reference, you can assign a value to it. When this runs,b
will be changed to 11. If you changed the initialization so thata
was, say, 8, thena
would be changed to 11. This is some code that might actually serve a purpose, unlike the other examples.Declares a function named foo that returns a reference to an
int
. What that examples fails to do is give you a definition of that function that you could compile. If we useNow we have a function that returns a reference to
bar
. since bar isstatic
it will live on after the call to the function so returning a reference to it is safe. Now if we doWhat happens is we assign 42 to
bar
since we assign to the reference and the reference is just an alias forbar
. If we call the function again likeIt would print 42 since we set
bar
to that above.The example code at the linked page is just a dummy function declaration. It does not compile, but if you had some function defined, it would work generally. The example meant "If you had a function with this signature, you could use it like that".
In your example,
foo
is clearly returning an lvalue based on the signature, but you return an rvalue that is converted to an lvalue. This clearly is determined to fail. You could do:and would succeed by changing the value of x, when saying:
In that context the & means a reference - so foo returns a reference to an int, rather than an int.
I'm not sure if you'd have worked with pointers yet, but it's a similar idea, you're not actually returning the value out of the function - instead you're passing the information needed to find the location in memory where that int is.
So to summarize you're not assigning a value to a function call - you're using a function to get a reference, and then assigning the value being referenced to a new value. It's easy to think everything happens at once, but in reality the computer does everything in a precise order.
If you're wondering - the reason you're getting a segfault is because you're returning a numeric literal '2' - so it's the exact error you'd get if you were to define a const int and then try to modify its value.
If you haven't learned about pointers and dynamic memory yet then I'd recommend that first as there's a few concepts that I think are hard to understand unless you're learning them all at once.