Regarding lvalue-to-rvalue conversion, when is it required?

1.2k views Asked by At

I've been reading quite many on the Internet and it seems that many people mentioned the following rules (but i couldn't find it in the standard),

The addition operator + (and all other binary operators) requires both operands to be rvalue, and the result is rvalue. And so on..

I checked the C++ standard, and it clearly states that (clause 3.10/2),

Whenever a glvalue appears in a context where a prvalue is expected, the glvalue is converted to a prvalue

(clause 5/9),

Whenever a glvalue expression appears as an operand of an operator that expects a prvalue for that operand, the lvalue-to-rvalue (4.1), array-to-pointer (4.2), or function-to-pointer (4.3) standard conversions are applied to convert the expression to a prvalue.

It uses a term the operand "expects" a prvalue. However, when I look into addition operator, multiplication operator etc, it only mentions that, the result is a prvalue, but it doesn't say anything on what the operands are "expected" to be.

Whether does the binary operator really expects the operands to be prvalue makes a difference in the following case,

int b = 2;
int a = b + 1;

If b is expected to be a prvalue, there will be a lvalue-to-rvalue conversion here, and then it will perform prvalue + prvalue and return a prvalue, and the result prvalue is assigned to an lvalue a.

However, if b is not required to be a prvalue, it would be lvalue + prvalue and the result is a prvalue.

I really want to know where does the standard explicitly or implicitly mentions that the rules for different operators? I check all the operators section and only a few operators that the standards explicitly mentions whether the operands and results shall be lvalue or rvalue. For most operators, the standard only mentions the result but not the operand requirement.

Thanks.


Btw, I found in Standard 5.19 regarding constant expression may very very "implicitly" imply that the binary operator require lvalue-to-rvalue conversion on operands. For more details, please refer to my previous question,

mixing use of constexpr and const?

A conditional-expression is a constant expression unless it involves one of the following as a potentially evaluated subexpression (3.2).

...

— an lvalue-to-rvalue conversion (4.1) unless it is applied to

———— a glvalue of integral or enumeration type that refers to a non-volatile const object with a preceding initialization, initialized with a constant expression

Thanks for reading.

2

There are 2 answers

1
Arelius On BEST ANSWER

So, this is generally one of those inferred and ill-specified parts of the standard; However, in 3.10

[ Note: some built-in operators expect lvalue operands. [ Example: built-in assignment operators all expect their left-hand operands to be lvalues. — end example ] Other built-in operators yield rvalues, and some expect them. [ Example: the unary and binary + operators expect rvalue arguments and yield rvalue results. — end example ] The discussion of each built-in operator in clause 5 indicates whether it expects lvalue operands and whether it yields an lvalue. — end note ]

Notice the poorly specified language "in clause 5 indicates whether it expects lvalue operands and whether it yields an lvalue".

Examination of Chapter 5 indicates that every case where an expression needs or returns an lvalue is enumerated, however very few cases dealing specifically with rvalues are enumerated, I think it's then assumed that the rest is assumed to be rvalues.

I also suspect it's poorly specified because from the perspective of the standard, it's not particularly important if the conversion is done implicitly or explicitly by the operator, regardless, the behavior should be the consistent and well-behaved.

0
ABu On

(First of all, sorry for my English. Corrections are absolutely wellcome)

The standard says:

§5.7-3 The result of the binary + operator is the sum of the operands. [...]

Let's suppose we have the expression e1 + e2, and the + operator selected is the built-in one, the expression is well-formed, e1 and e2 are arithmetic types or a casting to arithmetic type is available, and everything is OK, fine and perfect!

So, rule §5.7-3 applies. In other hand, each operand is an expressions:

§5-1 [Note: [...] An expression is a sequence of operators and operands that specifies a computation. An expression can result in a value and can cause side effects. — end note]

It says an expression can result in a value because of void expressions, like the delete expression or a voidfunction, but since we have said e1 + e2 is a perfectly-defined expression!, we can omit the verb "can", and so we can afirm that: an expression results in a value.

Last point: for arithmetical and logical built-in operators, I understand, although it isn't specified by the standard, only the value of its operands matter, irrespective of the value category of them.

I think that with being expressions is enough for implementing the built-in operator + (and other arithmetical operators), since only the value matters, and the value can be reached through the expression. For this reason, the Standard doesn't define them clearly.

All the same, this type of things are very bad structured. For example, I've found no place specifing, when an operator receive an object as operand and not a direct value (doubt that I'm currently trying to solve), if the operator should take directly its value for computing the operator, if the value is the result of evaluating the object, and so on. It's obvious that only values matters, but, what exactly says the Standard for these things is a sort of mystery.