How come the following works?
double doubleVal(double val) {
return val*2;
}
int main()
{
double myVal = 3.0;
double(*&&ptr)(double) = &doubleVal; // Why?
}
I don't understand why the function address can be converted to an rvalue reference.. isn't it an lvalue?
Your code is basically asking why:
using T = ...;
T someVal;
T*&& ref = &someVal;
works. While someVal is an lvalue, &someVal is a prvalue, which is a kind of rvalue. Any rvalue may be used to initialize an rvalue reference.
The compiler recognizes the syntax as being a function pointer
double(*ptr)(double) = &doubleVal;
The additional && is applied against ptr, not the properties of the function to which ptr will point
double(*&&ptr)(double) = &doubleVal;
accepts a reference to an rvalue, and the thing on the right is an rvalue - it doesn't have a name or an address until it is stored in ptr.
return &(&doubleVal); // warning - returning address of temporary
Related
Recently I was studying lvalue and rvalue concept.
When I do
int&z = 0 ;
I get an expected error like :
initial value of reference to non-const must be an lvalue
However, when I do this with a function that returns lvalue reference like:
int& get_value(){
static int x = 10;
return x;
}
//This line turns out to be valid...
get_value() = 20;
I wonder why get_value() = 20; is valid.
The error message makes it quite clear:
initial value of reference to non-const must be an lvalue
(emphasis mine). So long as the reference is initially bound to an l-value, everything is fine (so long as you don't use a reference to a stack local variable, of course). The reference returned from get_value is bound to x which is an l-value, and that's allowed.
Without the function, you are essentially writing:
int x = 10; // x is an l-value
int &get_x = x; // just a variable instead of a function
get_x = 20; // assignment is ok
which is clearly ok.
We have the following code example:
// lvalues:
//
int i = 42;
i = 43; // ok, i is an lvalue
int* p = &i; // ok, i is an lvalue
int& foo();
foo() = 42; // ok, foo() is an lvalue
int* p1 = &foo(); // ok, foo() is an lvalue
// rvalues:
//
int foobar();
int j = 0;
j = foobar(); // ok, foobar() is an rvalue
int* p2 = &foobar(); // error, cannot take the address of an rvalue
j = 42; // ok, 42 is an rvalue
I'm trying to understand why does a plain function definition as this:
int foobar();
is supposed to be an rvalue, while the same function but with an object reference as the return type, as this:
int& foobar();
is an lvalue. (The second part somehow comes naturally, because we specifically ask for and thus keep a reference when defining the function. However, the first example is hard to grasp for me, as I was expecting that the memory location of a function is somehow implicitly deducted, based on the assumption -that might be wrong-, that each function has its own, non changeable location in memory and, in conclusion, the first example should have also been an lvalue reference). Please try and explain this aspect, first.
I understand that:
An lvalue is an expression that refers to a memory location and allows us to take the address of that memory location via the & operator. An rvalue is an expression that is not an lvalue.
However, as stated above, I'm mostly interested in how functions, as opposed to or in correlation to simple objects, are treated regarding the lvalue/rvalue concept.
Thank you!
foobar() is not a function. It's a function call. The evaluation of it is the result of calling the function, i.e. an int which is an rvalue.
Here is how you would assign the function to a reference (which is a better test than taking its address):
int (&a)() = foo; // OK
int (&&b)() = foo; // OK
This is how you would assign the function address
int (*a)() = &foo; // OK
I understand that: "An lvalue is an expression that refers to a memory location and allows us to take the address of that memory location via the & operator. An rvalue is an expression that is not an lvalue."
Well... that's a pretty simplistic definition. Here are some links if you are interested in the subject:
What are rvalues, lvalues, xvalues, glvalues, and prvalues?
Value categories
Why does the first line not compile while the second line compiles?
float& t = float(10); // initial value of reference to non - const must be an lvalue
string& w = string("gg");
Does this imply that the string constructor returns a lvalue?
Constructor by the definition does not have a return value. What you're trying to perform is making a reference to a temporary value which is not allowed.
Good article to understand both lvalue and rvalue references is C++ Rvalue References Explained.
What you are getting is not what you are expecting:
float& ref = float(10);
What does happen here? float(10) creates a temporary float (not bound to anything), it is thus an rvalue. Therefore you cannot bind it to a non-const lvalue reference.
float const & cref = float(10); // OK!
The mechanics involved in this are the same for std::string. I am puzzled that you do not get a compiler error on the string example (I do with gcc 5.3.0)
Note that this has nothing to do with a so-called "constructor return value", because constructors have no such thing.
Quick query regarding universal references:
Let's say i have this code
int q = 10;
auto && wtf = &q;
This one compiles fine, but i have no idea what's happening behind the hood. It's taking a reference to an address? isn't that the pointer's job?
I was trying to deduce that auto&&'s type will be and i did it by:
int & test = &q //error
int && test = &q //error too
So what does it become? I need clarification on what's happening and what's the purpose of taking & from a universal reference? I am doing this because i am trying to understand std::bind since it can take address or pointers(which is the address of the being pointed aka pointer's value).
When you write &q you create a temporary value.
An rvalue [...] is an xvalue, a temporary object (12.2) or subobject thereof, or a value that is not associated with an object.
[ยง 3.10]
Those are best bound to rvalue references, so
auto && wtf = &q;
becomes an rvalue reference (&& and && stays &&) to the type of &q. This isn't int, it's int *. That's why your manual attempt failed.
If you would instead bind to a lvalue, like a local variable, then you get a lvalue reference:
int * qptr = &q;
auto && wtf2 = qptr;
// auto becomes (int *)&
// & combined with && becomes &
The whole thing can new seen in action here.
I am puzzled by the following code:
#include <iostream>
int main()
{
int x{};
int&& rvx = static_cast<int&&>(x);
++rvx;
std::cout << x << std::endl;
}
The output of it is 1. I don't understand how this works. The static_cast is supposed to cast the lvalue x into an xvalue, which is then assigned to rvx. Why does incrementing rvx lead to a change in x? Is this because the converted lvalue-to-rvalue is essentially sitting at the same memory location, but it is just considered now a rvalue? I was under the impression (which is probably false) that somehow the cast creates a temporary out of its argument.
rvalue reference is a reference. In this, it works just like any other reference.
An rvalue reference can bind to a temporary. This is what you'd get, for instance, if you write
int x{};
int&& rvx = +x;
But it doesn't need to bind to a temporary. By casting x to int&&, you've indicated to the compiler that that's okay too, that it may treat x as an rvalue to bind directly to the reference.