I am trying to understand and read that rvalues cannot be converted to lvalues. The following is fine
int x = 1; // x is an lvalue
int y = 2; // y is an lvalue
int z = x + y; // the "+" needs rvalues, so x and y are converted to rvalues
//(from lvalues) and an rvalue is returned
Now if I do
x = 5;
y = 6;
Aren't x and y converted to lvalues (from rvalues)?
Edit: The question in What are rvalues, lvalues, xvalues, glvalues, and prvalues? has little to no reference to conversion and no examples to explain.
It's important to be precise about what we're talking about.
In C++, an expression has a type, and can be either an lvalue or rvalue (value category)
An implicit conversion occurs when an expression of one (type, value category) occurs in a context where a different (type, value category) is expected.
An explicit conversion uses one of the language's cast operators, taking a subexpression of one (type, value category) as an operand, and yielding an expression of a different (type, value category) as the result.
An lvalue or xvalue can be implicitly converted to a prvalue; this is called the lvalue-to-rvalue conversion for historical reasons. The line
int z = x + y;
serves as an example of this implicit conversion. As the comment explains, the built-in + operator expects prvalues as its operands but we have supplied lvalues instead, so an implicit conversion occurs.
An lvalue can also be explicitly converted to an xvalue:
std::string s1 = static_cast<std::string&&>(s2); // i.e., std::move(s2)
Here s2 is an lvalue but we want to make sure the initializer is an xvalue so that the move constructor will be used, so we perform an explicit conversion.
An rvalue can be neither implicitly nor explicitly converted to an lvalue. For example, the following does not compile:
3++;
because the ++ operator requires an lvalue, and we have supplied an rvalue. Nor will the following compile, where we attempt to explicitly convert an rvalue to an lvalue:
static_cast<int&>(3)++;
(Note: the type of 3 is int, not const int. Constness is not the reason why we cannot modify 3.)
There is actually no conversion occurring in the assignments shown:
x = 5;
y = 6;
because when assigning to an int lvalue, a prvalue is expected as the right-hand operand, and a prvalue has been supplied. Although we are doing some sort of operation that has an rvalue as the source and an lvalue as the destination, this is not a conversion according to the rules of the language.
Lvalue kinda means "address". Rvalue kinda means "value". An expression is either an lvalue or an rvalue. As an expression x is an lvalue, however, in the expression z = x + y; the + operator needs data, so x and y are dereferenced. That is, the value at their addresses are fetched, and it is these rvalue values that are added together, producing an rvalue equal to their sum. The assignment operator needs an lvalue on the left and an rvalue on the right. It puts the value on the right into the address on the left, so z is not dereferenced, and is an lvalue.
A variable like x can't be said to be either an lvalue or an rvalue until you know its context.
Related
Why does the first return a reference?
int x = 1;
int y = 2;
(x > y ? x : y) = 100;
While the second does not?
int x = 1;
long y = 2;
(x > y ? x : y) = 100;
Actually, the second did not compile at all - "not lvalue left of assignment".
Expressions don't have return types, they have a type and - as it's known in the latest C++ standard - a value category.
A conditional expression can be an lvalue or an rvalue. This is its value category. (This is somewhat of a simplification, in C++11 we have lvalues, xvalues and prvalues.)
In very broad and simple terms, an lvalue refers to an object in memory and an rvalue is just a value that may not necessarily be attached to an object in memory.
An assignment expression assigns a value to an object so the thing being assigned to must be an lvalue.
For a conditional expression (?:) to be an lvalue (again, in broad and simple terms), the second and third operands must be lvalues of the same type. This is because the type and value category of a conditional expression is determined at compile time and must be appropriate whether or not the condition is true. If one of the operands must be converted to a different type to match the other then the conditional expression cannot be an lvalue as the result of this conversion would not be an lvalue.
ISO/IEC 14882:2011 references:
3.10 [basic.lval] Lvalues and rvalues (about value categories)
5.15 [expr.cond] Conditional operator (rules for what type and value category a conditional expression has)
5.17 [expr.ass] Assignment and compound assignment operators (requirement that the l.h.s. of an assignment must be a modifiable lvalue)
The type of the ternary ?: expression is the common type of its second and third argument. If both types are the same, you get a reference back. If they are convertable to each other, one gets chosen and the other gets converted (promoted in this case). Since you can't return an lvalue reference to a temporary (the converted / promoted variable), its type is a value type.
It cannot return a lvalue since it will have to implicitly promote the type of x to match the type of y (since both sides of : are not of the same type), and with that it has to create a temporary.
What does the standard say? (n1905)
Expressions 5.17 Assignment and compound assignment operators
5.17/3
If the second and third operand have different types, and either has (possibly cv-qualified) class type, an attempt is made to convert each of those operands to the type of the other. The process for determining whether an operand expression E1 of type T1 can be converted to match an operand expression E2 of type T2 is defined as follows:
— If E2 is an lvalue: E1 can be converted to match E2 if E1 can be implicitly converted (clause 4) to the type “reference to T2”, subject to the constraint that in the conversion the reference must bind directly (8.5.3) to E1.
— If E2 is an rvalue, or if the conversion above cannot be done:
— if E1 and E2 have class type, and the underlying class types are the same or one is a base class of the other: E1 can be converted to match E2 if the class of T2 is the same type as, or a base class of, the class of T1, and the cv-qualification of T2 is the same cv-qualification as, or a greater cv-qualification than, the cv-qualification of T1. If the conversion is applied, E1 is changed to an rvalue of type T2 that still refers to the original source class object (or the appropriate subobject thereof). [Note: that is, no copy is made. — end note] by copy-initializing a temporary of type T2 from E1 and using that temporary as the converted operand.
Otherwise (i.e., if E1 or E2 has a non class type, or if they both have class types but the underlying classes are not either the same or one a base class of the other): E1 can be converted to match E2 if E1 can be implicitly converted to the type that expression E2 would have if E2 were converted to an rvalue (or the type it has, if E2 is an rvalue).
Using this process, It is determined whether the second operand can be converted to match the third operand, and whether the third operand can be converted to match the second operand. If both can be converted, or one can be converted but the conversion is ambiguous, the program is ill-formed. If neither can be converted, the operands are left unchanged and further checking is performed as described below. If exactly one conversion is possible, that conversion is applied to the chosen operand and the converted operand is used in place of the original operand for the remainder of this section.
5.17/4
If the second and third operands are lvalues and have the same type, the result is of that type and is an lvalue and it is a bit-field if the second or the third operand is a bit-field, or if both are bit-fields.
5.17/5
Otherwise, the result is an rvalue. If the second and third operands do not have the same type, and either has (possibly cv-qualified) class type, overload resolution is used to determine the conversions (if any) to be applied to the operands (13.3.1.2, 13.6). If the overload resolution fails, the program is ill-formed. Otherwise, the conversions thus determined are applied, and the converted operands are used in place of the original operands for the remainder of this section.
One more example
int x = 1;
int y = 2;
long z = 3;
(true ? x : y) = 100; // x & y are SAME type so it returns Lvalue(so it can be LHS of =). x = 100, y = 2
(false ? x : y) = 100; // x & y are SAME type so it returns Lvalue(so it can be LHS of =). x = 1 , y = 100
// (true ? x : z) = 100; // Error: x & z are DIFFERENT types so it returns Rvalue (so it can NOT be LHS of =)
// (false ? x : z) = 100; // Error: x & z are DIFFERENT types so it returns Rvalue (so it can NOT be LHS of =)
Should this program output 0 or 1? In my reading and understanding of the cited paragraphs from the C++14 standard, it should print 1, but both GCC and clang prints 0 (because the deduced type is A const instead of A const&):
#include <iostream>
struct A {};
int main()
{
A a;
A const& ra = std::move(a); // #1
std::cout << std::is_same<decltype(true ? ra : std::move(a)),
A const&>::value; // Prints 0
}
In this case, ra is a A const lvalue, and std::move(a) is a A xvalue, both of class-types. According to the standard about the conditional operator (emphasis mine), the result should be an lvalue of type A const, and thus the decltype result must be A const&:
[expr.cond]/3 Otherwise, if the second and third operand have different types and either has (possibly cv-qualified) class
type, or if both are glvalues of the same value category and the same type except for cv-qualification, an
attempt is made to convert each of those operands to the type of the other. The process for determining
whether an operand expression E1 of type T1 can be converted to match an operand expression E2 of type
T2 is defined as follows:
— If E2 is an lvalue: E1 can be converted to match E2 if E1 can be implicitly converted (Clause 4) to the
type “lvalue reference to T2”, subject to the constraint that in the conversion the reference must bind directly (8.5.3) to an lvalue.
[...]
In this case, E2 is ra, which is a lvalue, and the other can be implicitely converted to "lvalue reference to T2", as shown in line // #1. "lvalue reference to T2" is translated as A const&, so, std::move(a) binds directly to a lvalue of type A const, and after the conversion, both operands have same type and value category, and thus:
[expr.cond]/3 If the second and third operands are glvalues of the same value category and have the same type, the result is of that type and value category [...].
So, the operator result should be an lvalue and the decltype result should be a reference, and thus the program should print 1.
The question is awkwardly worded. You should instead ask what the type and value category of the expression true ? ra : std::move(a) should be. The answer to that question is a prvalue of type A const. This subsequently means the program should print 0, as I think every compiler correctly does.
The rules for ?: are fairly complex. In this case, we have two expressions of class type that we try to see if we can convert to each other, based on a limited subset of rules.
Attempting the conversion ra → std::move(a) fails. We first try with a target type is A&& which can't bind directly to ra. We then try the backup plan in (3.3.1) since the two expressions have the same underlying class type, but our target expression is not at least as cv-qualified as the source expression, so this also fails.
Attempting the conversion std::move(a) → ra fails (3.1) because we need to bind directly to an lvalue (we can bind an rvalue to a const lvalue reference, but here we are required to bind an lvalue). But, the (3.3.1) backup succeeds because now the target type is at least as cv-qualified as the source.
Hence, we apply the conversion and we continue as if the second operand were an lvalue of type A const but the third operand is now a prvalue of type A const (instead of an xvalue of type A).
(4) fails, because they're not of the same value category.
Hence, the result is a prvalue. And since they have the same type, the result is of that type: A const.
Can anyone explain me why this is true:
char *p;
short i;
long l;
(long *) p = &l ; /* Legal cast */
(long) i = l ; /* Illegal cast */
I know it has something to do with lvalue and rvalue but shouldn't (long *) p be a rvalue?
edit:
sorry it seems I confused myself and others, I asked this while reading "this MDSN" and I was surprised to see this syntax, I see it's a special feature that allows to convert lvalue into lvalue as long as it's the same size.
Neither of these expressions are legal, they should both fail to compile.
C++11, 5.17.1:
The assignment operator (=) and the compound assignment operators all group right-to-left. All require a modifiable lvalue as their left operand and return an lvalue referring to the left operand.
5.4:
Explicit type conversion (cast notation) [expr.cast]
1 The result of the expression (T) cast-expression is of type T. The result is an lvalue if T is an lvalue reference type or an rvalue reference to function type and an xvalue if T is an rvalue reference to object type; otherwise the result is a prvalue.
So both expressions violate these constraints.
shouldn't (long *) p be a rvalue?
It is.
They're both prvalues and, as such, both statements are ill-formed:
[C++03: 5.4/1]: The result of the expression (T) cast-expression is of type T. The result is an lvalue if T is a reference type, otherwise the result is an rvalue.
[C++11: 5.4/1]: The result of the expression (T) cast-expression is of type T. The result is an lvalue if T is an lvalue reference type or an rvalue reference to function type and an xvalue if T is an rvalue reference to object type; otherwise the result is a prvalue. [..]
GCC 4.8 rejects your "legal cast", but Visual Studio has an extension that accepts this (for no apparent reason).
The result of a value conversion is an rvalue. You cannot assign to rvalues of fundamental types.
In other words, for int a = 10;, a is an lvalue of type int, but (long) a is a temporary rvalue of type long, and you cannot assign to the temporary. Likewise for pointers.
Why do you think your cast is legal? I'm getting error C2106: '=' : left operand must be l-value on both casts.
This shouldn't be legal. If you really want to do it, you have to cast it like this:
(long*&)p = &l; // equivalent to *(long**)&p = &l
But don't do that unless you know what you are doing.
local lvalue references-to-const and rvalue references can extend the lifetime of temporaries:
const std::string& a = std::string("hello");
std::string&& b = std::string("world");
Does that also work when the initializer is not a simple expression, but uses the conditional operator?
std::string&& c = condition ? std::string("hello") : std::string("world");
What if one of the results is a temporary object, but the other one isn't?
std::string d = "hello";
const std::string& e = condition ? d : std::string("world");
Does C++ mandate the lifetime of the temporary be extended when the condition is false?
The question came up while answering this question about non-copyable objects.
Both of those are fine.
§5.16 says (extraordinarily abridged):
2 If either the second or the third operand has type void
Nope.
3 Otherwise, if the second and third operand have different types
Nope.
4 If the second and third operands are glvalues of the same value category
Nope. (In the first, both are prvalues and in the second one is a glvalue and one is a prvalue.)
5 Otherwise, the result is a prvalue
Okay, so both of these result in prvalues. So the binding is fine, but what's the binding to?
6 Lvalue-to-rvalue (4.1), array-to-pointer (4.2), and function-to-pointer (4.3) standard conversions are per- formed on the second and third operands.
Okay, so both are now rvalues if they weren't already.
6 (continued) After those conversions, one of the following shall hold:
The second and third operands have the same type; the result is of that type. If the operands have class type, the result is a prvalue temporary of the result type, which is copy-initialized from either the second operand or the third operand depending on the value of the first operand.
Okay, so it's either std::string(first_operand) or std::string(second_operand).
Regardless, the result of the conditional expression is a new prvalue temporary, and it's that value that's extended by binding to your references.
std::string d = "hello";
const std::string& e = condition ? d : std::string("world");
Does C++ mandate the lifetime of the temporary be extended when the condition is false?
It will be. The conditional is an rvalue expression, and when bound with a const reference the compiler will create an unnamed object and bind the reference to it. What I am not 100% sure is whether the temporary whose lifetime is extended is std::string("world") or whether a copy of it is (conceptually) made (and elided).
Given:
int main() {
int x = 0;
int y = x; // <---
}
Could someone please tell me which clause of the standard (2003 preferred) mandates the conversion of the expression x from lvalue to rvalue in the initialisation of the object y?
(Or, if I'm mistaken and no such conversion takes place, then I'd like to learn that too!)
I find it easier (if maybe not 100% precise) to think of lvalue-s as real objects and rvalue-s as the value stored in the object. The expression x is an lvalue expression that refers to the object x defined in the first line, but when used as the right hand side of an assignment to a type that is not a user defined type the actual value is read, and that is where the conversion from lvalue to rvalue is performed: reading the contents of the object.
As to the specific clause in the standard that dictates that conversion... well, the closest that I can think is 4.1 [conv.lvalue]/2 (Lvalue to Rvalue conversion):
The value contained in the object indicated by the lvalue is the rvalue result.
The requirement that the right hand side of the assignment is an rvalue is either implicit or missing from 5.17 [expr.ass], but that is the case or else the following expression would be an error since the rhs is an rvalue and there is no rvalue-to-lvalue conversion:
int x = 5;
EDIT: For initialization, 8.5 [dcl.init]/14, last bullet (which refers to fundamental types) states (emphasis mine):
Otherwise, the initial value of the object being initialized is the (possibly converted) value of the initializer expression. [...]
That value there means that the lvalue expression in your example is read (i.e. converted to an rvalue). At any rate the previous paragraph that referred to assignment could be applied here: if initialization required an lvalue rather than an rvalue, the expression int i = 0; would be ill-formed.
I do believe that this is intuitive to some degree (what others already said - the value is needed, so there is an obvious need to convert the object designator to the value contained therein). The best I could come up with, by 4p3:
An expression e can be implicitly converted to a type T if and only if the declaration "T t=e;" is well-formed, for some invented temporary variable t (8.5). The effect of the implicit conversion is the same as performing the declaration and initialization and then using the temporary variable as the result of the conversion. The result is an lvalue if T is a reference type (8.3.2), and an rvalue otherwise. The expression e is used as an lvalue if and only if the initialization uses it as an lvalue.
Note the "if and only if" at the end - the initializer therefor is used as an rvalue, because the initialization uses it as an rvalue (result of the conversion). So by 3.10p7
Whenever an lvalue appears in a context where an rvalue is expected, the lvalue is converted to an rvalue; see 4.1, 4.2, and 4.3.
EDIT: The paragraph for entering 4p3 can be found at 8.5p16, last bullet:
Otherwise, the initial value of the object being initialized is the (possibly converted) value of the initializer expression.
Also note the comments below.
Is this what you're looking for:
§3.10/7
Whenever an lvalue appears in a context where an rvalue is expected, the lvalue is converted to an rvalue; see 4.1, 4.2, and 4.3.
And I think when you write int y = x, it basically copies the value contained in the object x which is a lvalue, but the value itself is an rvalue, hence the context expects an rvalue.
§4.1/2 says,
The value contained in the object indicated by the lvalue is the rvalue result.
Maybe these two quotations clarify your doubt. Correct me if my understanding is wrong. I would like to learn new things.
#Tomalak's comment:
My problem with this is that int& y = x; is valid, so in this case of course x may not be an rvalue. I don't know how irrelevant the difference in my example makes that, though
Well int &y = x does NOT copy the value. It just creates an alias of the object itself. But as I previously said int y = x, basically copies the value which is an rvalue. Hence, the context expects an rvalue, as a copying is being done here.
The initializer has the follwing grammar:
initializer:
= initializer-clause
( expression-list )
initializer-clause:
assignment-expression
{ initializer-list ,opt }
{ }
In your example, x is an assignment-expression which follows this chain of grammar productions:
conditional-expression ==>
logical-or-expression ==>
logical-and-expression ==>
inclusive-or-expression ==>
exclusive-or-expression ==>
and-expression ==>
equality-expression ==>
relational-expression ==>
shift-expression ==>
additive-expression ==>
multiplicative-expression ==>
pm-expression ==>
cast-expression ==>
unary-expression ==>
postfix-expression ==>
primary-expression ==>
id-expression ==>
unqualified-id ==>
identifier
And an identifier "is an lvalue if the entity is a function or variable" (5.1/4 "Primary expressions").
So in your example, the expression to the right of the = is an expression that happens to be an lvalue. It could be an rvalue of course, but it doesn't have to be. And there is no mandated lvalue-to-rvalue conversion.
I'm not sure what the value in knowing this is, though.
3.10 Lvalues and rvalues
1 Every expression is either an lvalue
or an rvalue.
2 An lvalue refers to an object or
function. Some rvalue
expressions—those of class or
cvqualified class type—also refer to
objects.47)
3 [Note: some builtin operators and
function calls yield lvalues.
[Example: if E is an expression of
pointer type, then *E is an lvalue
expression referring to the object or
function to which E points. As another
example, the function int& f(); yields
an lvalue, so the call f() is an
lvalue expression. ]
[Note: some builin operators expect lvalue operands. [Example: builtin
assignment operators all expect their
left hand operands to be lvalues. ]
Other builtin operators yield rvalues,
and some expect them. [Example: the
unary and binary + operators expect
rvalue arguments and yield rvalue
results. ] The discussion of each
builtin operator in clause 5 indicates
whether it expects lvalue operands and
whether it yieldsan lvalue. ]
5 The result of calling a function
that does not return a reference is an
rvalue. User defined operators are
functions, and whether such operators
expect or yield lvalues is determined
by their parameter and return types.
6 An expression which holds a
temporary object resulting from a cast
to a nonreference type is an rvalue
(this includes the explicit creation
of an object using functional notation
(5.2.3)).
7 Whenever an lvalue appears in a context where an rvalue is expected,
the lvalue is converted to an rvalue;
see 4.1, 4.2, and 4.3.
8 The discussion of reference
initialization in 8.5.3 and of
temporaries in 12.2 indicates the
behavior of lvalues and rvalues in
other significant contexts.
9 Class rvalues can have cvqualified
types; nonclass rvalues always have
cvunqualified types. Rvalues shall
always have complete types or the void
type; in addition to these types,
lvalues can also have incomplete
types.
10 An lvalue for an object is
necessary in order to modify the
object except that an rvalue of class
type can also be used to modify its
referent under certain circumstances.
[Example: a member function called for
an object (9.3) can modify the object.
]
11 Functions cannot be modified, but
pointers to functions can be
modifiable.
12 A pointer to an incomplete type can
be modifiable. At some point in the
program when the pointed to type is
complete, the object at which the
pointer points can also be modified.
13 The referent of a constqualified
expression shall not be modified
(through that expression), except that
if it is of class type and has a
mutable component, that component can
be modified (7.1.5.1).
14 If an expression can be used to
modify the object to which it refers,
the expression is called modifiable. A
program that attempts to modify an
object through a nonmodifiable lvalue
or rvalue expression is illformed.
15 If a program attempts to access the
stored value of an object through an
lvalue of other than one of the
following types the behavior is
undefined48): — the dynamic type of
the object, — a cvqualified version of
the dynamic type of the object, — a
type that is the signed or unsigned
type corresponding to the dynamic type
of the object, — a type that is the
signed or unsigned type corresponding
to a cvqualified version of the
dynamic type of the object, — an
aggregate or union type that includes
one of the aforementioned types among
its members (including, recursively, a
member of a subaggregate or contained
union), — a type that is a (possibly
cvqualified) base class type of the
dynamic type of the object, — a char
or unsigned char type.