Universal reference deduction if the argument is address - c++

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.

Related

how the binding of const type works in c++?

why this binding is ok
int main()
{
double d = 4.56;
const int &r = d;
return 0;
}
but this is not
int main()
{
double d = 4.56;
int &r = d;
return 0;
}
can anyone explain me while the first one compile but second one shows error
When you bind to a converted type (the double has to be converted to an int), you get a prvalue, since the converted int is a temporary with no address in memory. Therefore, binding a regular reference to it doesn't work, because they can only bind to glvalues. const type references can bind to prvalues, so the first one compiles still. Source: https://en.cppreference.com/w/cpp/language/value_category
An int reference cannot be bound to an object of type double, because the types mismatch.
So in order to make the initialization of the reference work at all, a new temporary object of the correct type int must be created. This is possible because there is an implicit conversion sequence from double to int.
The reference should then bind to this temporary, i.e. to a rvalue expression, but only const lvalue references are allowed to bind to rvalues. Non-const lvalue references are not allowed to do that, making the second program ill-formed.
Note that in the first program, although the reference is bound to a temporary object that would usually be destroyed at the end of the full-expression that it was created in, binding to a reference extends the lifetime of that temporary object to the lifetime of the reference. So using r in the first program is actually ok.
However, access through r will not refer to d, but to that new temporary object that is independent of d, which may be surprising, and therefore I think it is not a good idea to write like that. Use auto& or const auto& to make sure that r will certainly refer to d and that there is never any implicit conversion happening due to a type mismatch. If you want the conversion, just use int instead of a reference to int.

Are return types considered as rvalues?

Just a simple question, i am trying to simulate a bad practice when it comes to returning &&. I am aware that it's a bad practice.
Here is an example
//dummy is just an empty class
dummy && crashtest(){
dummy temp;
return std::move(temp);
}
int main() {
dummy && k = crashtest();
return 0;
}
This is a bad practice because k now holds a reference to the destructed temp inside the function.
I tried a different approach by doing something like this inside my main:
dummy l; //generate temp
dummy && k = std::move(l); //return value
dummy && d = k; // copy
though l won't really be destroyed, how come it won't let me compile? I get an error saying that i am trying to bind an lvalue. isn't it the same as what happens in function? From my understanding, what happened in function was:
temp is created -> std::move(temp) -> return type dummy&& receives it -> k is equalized to the return type temporary.
I need clarification. Is the return type considered an rvalue ?
Bonus question: what happens if an rvalue reference variable is equalized to an rvalue reference variable? &&lhs = &&rhs, does lhs takes the rhs reference?
Returning an rvalue reference from a function will most likely cause a dangling reference(the reference exists, but the temporary object that it refers to has been destroyed).
This is actually called an xvalue(an "eXpiring" value) in the standard.

Binding function to rvalue reference

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

why is reference initialization with 'operator ++' gives error

#include<iostream.h>
int main()
{
int m = 2;
int &x = m++;
cout<<m;
return 0;
}
this code should gives
OUTPUT:
3
but this code gives error:
invalid initialization of non-const reference of type 'int&' from a temporary of type 'int'.
Post increment operator returns a temporary object with the value of m before increment.
Non const lvalue references can't be bound to temporary objects. Thus, the compiler rightfully complains.
m++ has to increase m (as a side effect), but evaluate to the original value. It does that by returning a temporary variable holding the value of m before increment.
An non-const l-value reference cannot bind to a temporary object.
You could write:
int &x = ++m;
This works because the pre–increment operator has to return the value after the increment, thus being able to evaluate to an l-value reference to m.
But I wouldn’t recommend that for clarity sake.
You can't use post increment to assign references - it is a temporary object
Here
int &x = m++;
you are assigning a temporary object (right side) to a reference(left side) which doesnt make any sense.
Instead,write:
int &x = ++m;

error: invalid initialization of non-const reference of type ‘int&’ from an rvalue of type ‘int’

Wrong form:
int &z = 12;
Correct form:
int y;
int &r = y;
Question:
Why is the first code wrong? What is the "meaning" of the error in the title?
C++03 3.10/1 says: "Every expression is either an lvalue or an rvalue." It's important to remember that lvalueness versus rvalueness is a property of expressions, not of objects.
Lvalues name objects that persist beyond a single expression. For example, obj , *ptr , ptr[index] , and ++x are all lvalues.
Rvalues are temporaries that evaporate at the end of the full-expression in which they live ("at the semicolon"). For example, 1729 , x + y , std::string("meow") , and x++ are all rvalues.
The address-of operator requires that its "operand shall be an lvalue". if we could take the address of one expression, the expression is an lvalue, otherwise it's an rvalue.
&obj; // valid
&12; //invalid
int &z = 12;
On the right hand side, a temporary object of type int is created from the integral literal 12, but the temporary cannot be bound to non-const reference. Hence the error. It is same as:
int &z = int(12); //still same error
Why a temporary gets created? Because a reference has to refer to an object in the memory, and for an object to exist, it has to be created first. Since the object is unnamed, it is a temporary object. It has no name. From this explanation, it became pretty much clear why the second case is fine.
A temporary object can be bound to const reference, which means, you can do this:
const int &z = 12; //ok
C++11 and Rvalue Reference:
For the sake of the completeness, I would like to add that C++11 has introduced rvalue-reference, which can bind to temporary object. So in C++11, you can write this:
int && z = 12; //C+11 only
Note that there is && intead of &. Also note that const is not needed anymore, even though the object which z binds to is a temporary object created out of integral-literal 12.
Since C++11 has introduced rvalue-reference, int& is now henceforth called lvalue-reference.
12 is a compile-time constant which can not be changed unlike the data referenced by int&. What you can do is
const int& z = 12;
Non-const and const reference binding follow different rules
These are the rules of the C++ language:
an expression consisting of a literal number (12) is a "rvalue"
it is not permitted to create a non-const reference with a rvalue: int &ri = 12; is ill-formed
it is permitted to create a const reference with a rvalue: in this case, an unnamed object is created by the compiler; this object will persist as long as the reference itself exist.
You have to understand that these are C++ rules. They just are.
It is easy to invent a different language, say C++', with slightly different rules. In C++', it would be permitted to create a non-const reference with a rvalue. There is nothing inconsistent or impossible here.
But it would allow some risky code where the programmer might not get what he intended, and C++ designers rightly decided to avoid that risk.
References are "hidden pointers" (non-null) to things which can change (lvalues). You cannot define them to a constant. It should be a "variable" thing.
EDIT::
I am thinking of
int &x = y;
as almost equivalent of
int* __px = &y;
#define x (*__px)
where __px is a fresh name, and the #define x works only inside the block containing the declaration of x reference.