When is lvalue-to-rvalue conversion required?

Z

ZMZ

I've read from a number of sources about the following statements,
they make sense to me but I can't find similar statement in the
standard. My question is: are the following statements true? Thanks.

The addition (multiplication, etc) operator expects both of its two
operands to be rvalue, and the result of the expression is rvalue. So
there is definitely an lvalue-to-rvalue conversion if the supplied
operands are lvalues.

The left side of assignment operator is expected to be lvalue, and the
right side of the assignment operator is expected to be rvalue. So if
the right side is an lvalue, lvalue-to-rvalue conversion will be
performed too.

There are also something slightly different statements from the
Internet, e.g., somebody in his tutorial on lvalue and rvalue thinks
that, the addition etc operator operand can be lvalue or rvalue, so
according to his statement, there's no need to have an lvalue-to-
rvalue conversion if the supplied operand is lvalue.

Thanks for reading.
 
P

Paul

ZMZ said:
I've read from a number of sources about the following statements,
they make sense to me but I can't find similar statement in the
standard. My question is: are the following statements true? Thanks.

The addition (multiplication, etc) operator expects both of its two
operands to be rvalue, and the result of the expression is rvalue. So
there is definitely an lvalue-to-rvalue conversion if the supplied
operands are lvalues.

The left side of assignment operator is expected to be lvalue, and the
right side of the assignment operator is expected to be rvalue. So if
the right side is an lvalue, lvalue-to-rvalue conversion will be
performed too.
Thats certainly one way to over-complicate a simple arithmetic expression.
There are also something slightly different statements from the
Internet, e.g., somebody in his tutorial on lvalue and rvalue thinks
that, the addition etc operator operand can be lvalue or rvalue, so
according to his statement, there's no need to have an lvalue-to-
rvalue conversion if the supplied operand is lvalue.

Thanks for reading.
I guess I could play around with those words and make them mean whatever I
want them to mean. its such a confusication.

I think you look to much into , what is a very simple arithmethic
expression, why are you intereseted in this confusication?
 
Z

ZMZ

Thats certainly one way to over-complicate a simple arithmetic expression..



I guess I could play around with those words and make them mean whatever I
want them to mean. its such a confusication.

I think you look to much into , what is a very simple arithmethic
expression, why are you intereseted in this confusication?

Hi Paul, I am interested in it because recently I am confused about
some statements in Standard N3225 regarding constant expressions.

As far as what I can understand, const has problem because const data
are not guaranteed to be a compile time constants, see the following
example (from standard),

struct S {
static const int size;
};
const int limit = 2 * S::size; // dynamic initialization
const int S::size = 256;

So, constexpr is proposed to solve this problem. The following
shouldn't work!

struct S {
static const int size;
};
constexpr int limit = 2 * S::size; // shall be error in my
understanding
const int S::size = 256;

As in 7.1.5/9, we see the constexpr that refers to object,

A constexpr specifier used in an object declaration declares the
object as const. ....(unrelated).... Otherwise, every full-expression
that appears in its initializer shall
be a constant expression. ....(unrelated)....

In my understanding, it means that, constexpr int limit = 2 * S::size;
this is illegal because S::size is not a constant expression because
it hasn't been initialized yet.

Now let's look at 5.19 constant expressions,

A conditional-expression is a constant expression unless it involves
one of the following as a potentially evaluated
subexpression:

Then 5.19 listed many things that are not considered constant
expression, but to my surprise, it doesn't mention that UNINITIALIZED
const static is not a constant expression. There is one clause though,
that says,

— 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, or

Here is the only place I find that the standard put constraint of
initialization on constant expression: if a glvalue is of integral or
enumeration that refers to a const object that is initialized, and
that glvalue is participated into lvalue-to-rvalue conversion, then it
is considered as constant expression.

So it comes to my current confusion, is lvalue-to-rvalue conversion
shall be applied to every +, *, / and = operators? If so, then the
clause in 5.19 "— an lvalue-to-rvalue conversion (4.1) unless it is
applied to" will cover many cases and make sense that uninitialized
right hand side isn't a constant expression.

If not so, I will say that 5.19 didn't cover all cases? At least I
can't find any match to say S::size in the above example isn't a
constant expression.
 
P

Paul

I've read from a number of sources about the following statements,



Thats certainly one way to over-complicate a simple arithmetic expression.



I guess I could play around with those words and make them mean whatever I
want them to mean. its such a confusication.

I think you look to much into , what is a very simple arithmethic
expression, why are you intereseted in this confusication?

--Hi Paul, I am interested in it because recently I am confused about
--some statements in Standard N3225 regarding constant expressions.

--As far as what I can understand, const has problem because const data
--are not guaranteed to be a compile time constants, see the following
--example (from standard),

--struct S {
--static const int size;
--};
--const int limit = 2 * S::size; // dynamic initialization
--const int S::size = 256;

--So, constexpr is proposed to solve this problem. The following
--shouldn't work!

--struct S {
--static const int size;
--};
--constexpr int limit = 2 * S::size; // shall be error in my
--understanding
--const int S::size = 256;

--As in 7.1.5/9, we see the constexpr that refers to object,

--A constexpr specifier used in an object declaration declares the
--object as const. ....(unrelated).... Otherwise, every full-expression
--that appears in its initializer shall
--be a constant expression. ....(unrelated)....

--In my understanding, it means that, constexpr int limit = 2 * S::size;
--this is illegal because S::size is not a constant expression because
--it hasn't been initialized yet.

Yes this seems unclear, especially since there are two very similar terms
i.e:
constexpr
and
constant expression
which seem to be unrelated.


--Now let's look at 5.19 constant expressions,

--A conditional-expression is a constant expression unless it involves
--one of the following as a potentially evaluated
--subexpression:

Now this seems to be talking specifically about a conditional expression
i.e:
an if statement.

--Then 5.19 listed many things that are not considered constant
--expression, but to my surprise, it doesn't mention that UNINITIALIZED
--const static is not a constant expression. There is one clause though,
--that says,

— 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, or

--Here is the only place I find that the standard put constraint of
--initialization on constant expression: if a glvalue is of integral or
--enumeration that refers to a const object that is initialized, and
--that glvalue is participated into lvalue-to-rvalue conversion, then it
--is considered as constant expression.

--So it comes to my current confusion, is lvalue-to-rvalue conversion
--shall be applied to every +, *, / and = operators? If so, then the
--clause in 5.19 "— an lvalue-to-rvalue conversion (4.1) unless it is
--applied to" will cover many cases and make sense that uninitialized
--right hand side isn't a constant expression.

--If not so, I will say that 5.19 didn't cover all cases? At least I
--can't find any match to say S::size in the above example isn't a
--constant expression.

My rules are to initialise contants where there are declared, but in statics
I guess I woud initialise it immediately after the class definition.
I don't think the keyword constexpr existed when I learned C++, thankyou for
exposing me to this.

I can understand you wanting to understand the rules of the language , but I
can't help there I'm afraid.
I have never got so deeply into the rules of constantness.

GL , I'm sure some expert on the standard, or a compiler developer will be
able to explain what is going on.

Paul.
 
J

James Kanze

I've read from a number of sources about the following statements,
they make sense to me but I can't find similar statement in the
standard. My question is: are the following statements true? Thanks.
The addition (multiplication, etc) operator expects both of its two
operands to be rvalue, and the result of the expression is rvalue. So
there is definitely an lvalue-to-rvalue conversion if the supplied
operands are lvalues.
The left side of assignment operator is expected to be lvalue, and the
right side of the assignment operator is expected to be rvalue. So if
the right side is an lvalue, lvalue-to-rvalue conversion will be
performed too.

Both of the above are true.
There are also something slightly different statements from the
Internet, e.g., somebody in his tutorial on lvalue and rvalue thinks
that, the addition etc operator operand can be lvalue or rvalue, so
according to his statement, there's no need to have an lvalue-to-
rvalue conversion if the supplied operand is lvalue.

Loosely speaking, since the lvalue to rvalue conversion is
always possible, anywhere an rvalue is required, an lvalue can
be used.

Historically, IIRC, K&R didn't use the term rvalue. Lvalue was
something like an attribute that an expression had, or didn't
have; expressions either required it, or didn't. In the end, it
comes out to the same thing in most cases, just expressed
differently. The one case where it might make a difference is
when the lvalue to rvalue conversion triggers undefined
behavior; e.g. when accessing an uninitialized variable: you can
use an uninitialized variable as an lvalue (e.g. on the left
side of an assignment operator), but not as an rvalue (on the
right side of an assignment operator, or as an operand to the
+ operator).
 
Z

ZMZ

--Hi Paul, I am interested in it because recently I am confused about
--some statements in Standard N3225 regarding constant expressions.

--As far as what I can understand, const has problem because const data
--are not guaranteed to be a compile time constants, see the following
--example (from standard),

--struct S {
--static const int size;
--};
--const int limit = 2 * S::size; // dynamic initialization
--const int S::size = 256;

--So, constexpr is proposed to solve this problem. The following
--shouldn't work!

--struct S {
--static const int size;
--};
--constexpr int limit = 2 * S::size; // shall be error in my
--understanding
--const int S::size = 256;

--As in 7.1.5/9, we see the constexpr that refers to object,

--A constexpr specifier used in an object declaration declares the
--object as const.  ....(unrelated).... Otherwise, every full-expression
--that appears in its initializer shall
--be a constant expression. ....(unrelated)....

--In my understanding, it means that, constexpr int limit = 2 * S::size;
--this is illegal because S::size is not a constant expression because
--it hasn't been initialized yet.

Yes this seems unclear, especially since there are two very similar terms
i.e:
constexpr
and
constant expression
which seem to be unrelated.

--Now let's look at 5.19 constant expressions,

--A conditional-expression is a constant expression unless it involves
--one of the following as a potentially evaluated
--subexpression:

Now this seems to be talking specifically about a conditional expression
i.e:
an if statement.

--Then 5.19 listed many things that are not considered constant
--expression, but to my surprise, it doesn't mention that UNINITIALIZED
--const static is not a constant expression. There is one clause though,
--that says,

� 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, or

--Here is the only place I find that the standard put constraint of
--initialization on constant expression: if a glvalue is of integral or
--enumeration that refers to a const object that is initialized, and
--that glvalue is participated into lvalue-to-rvalue conversion, then it
--is considered as constant expression.

--So it comes to my current confusion, is lvalue-to-rvalue conversion
--shall be applied to every +, *, / and = operators? If so, then the
--clause in 5.19 "� an lvalue-to-rvalue conversion (4.1) unless it is
--applied to" will cover many cases and make sense that uninitialized
--right hand side isn't a constant expression.

--If not so, I will say that 5.19 didn't cover all cases? At least I
--can't find any match to say S::size in the above example isn't a
--constant expression.

My rules are to initialise contants where there are declared, but in statics
I guess I woud  initialise it immediately after the class definition.
I don't think the keyword constexpr existed when I learned C++, thankyou for
exposing me to this.

I can understand you wanting to understand the rules of the language , but I
can't help there I'm afraid.
I have never got so deeply into the rules of constantness.

GL , I'm sure some expert on the standard, or a compiler developer will be
able to explain what is going on.

Paul.

Thanks. I think I might be over focusing on the details.
 
Z

ZMZ

Both of the above are true.


Loosely speaking, since the lvalue to rvalue conversion is
always possible, anywhere an rvalue is required, an lvalue can
be used.

Historically, IIRC, K&R didn't use the term rvalue.  Lvalue was
something like an attribute that an expression had, or didn't
have; expressions either required it, or didn't.  In the end, it
comes out to the same thing in most cases, just expressed
differently.  The one case where it might make a difference is
when the lvalue to rvalue conversion triggers undefined
behavior; e.g. when accessing an uninitialized variable: you can
use an uninitialized variable as an lvalue (e.g. on the left
side of an assignment operator), but not as an rvalue (on the
right side of an assignment operator, or as an operand to the
+ operator).

Thanks. This is what I wanted to know.
 
Z

ZMZ

I just learnt from my StackOverflow on the same question, and Arelius
told me that, in the standard 3.10 (only in C++98 and 2003 standard,
not present in N3225),

[ 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 ]
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,049
Latest member
Allen00Reed

Latest Threads

Top