f



rvalue or lvalue?

Hi all,

Consider the following example:

struct Test {
    const Test& operator=( const Test &) const{
        return *this;
    }
};

int main(int argc, char* argv[])
{
    Test() = Test();
	return 0;
}

This adds a funny twist to the meaning lvalue, because in this case
every rvalue is an lvalue as well ;)

Best,
John

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
jtorjo
11/9/2003 2:21:28 PM
comp.lang.c++.moderated 10738 articles. 1 followers. allnor (8506) is leader. Post Follow

11 Replies
407 Views

Similar Articles

[PageSpeed] 43

> struct Test {
>     const Test& operator=( const Test &) const{
>         return *this;
>     }
> };

> int main(int argc, char* argv[])
> {
>     Test() = Test();
> return 0;
> }
>
> This adds a funny twist to the meaning lvalue, because in this case
> every rvalue is an lvalue as well ;)

Not really--it's just that rvalues of this type support assignment.

You shouldn't be able to execute &Test(), for example.


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Andrew
11/9/2003 10:36:57 PM
John Torjo wrote:

> Consider the following example:
> 
> struct Test {
>     const Test& operator=( const Test &) const{
>         return *this;
>     }
> };
> 
> int main(int argc, char* argv[])
> {
>     Test() = Test();
> return 0;
> }
> 
> This adds a funny twist to the meaning lvalue, because in this case
> every rvalue is an lvalue as well ;)

If you look at the title, the document pointed to is ancient, mostly
C-related, but still instructive...

        http://members.home.nl/r.f.pels/articles/misc/rlvalue.txt

-- 
Ruurd
..o.
...o
ooo

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
R
11/9/2003 10:49:59 PM
On 9 Nov 2003 09:21:28 -0500, jtorjo@yahoo.com (John Torjo) wrote:

> Consider the following example:

> struct Test {
>     const Test& operator=( const Test &) const{
>         return *this;
>     }
> };

> int main(int argc, char* argv[])
> {
>     Test() = Test();
> 	return 0;
> }

> This adds a funny twist to the meaning lvalue, because in this case
> every rvalue is an lvalue as well ;)

Your non-standard operator= reduced the possibilities.  If you stick to
the standard way, you can do more.

   (Test() = Test()) = Test();

What's the problem?  There is a standard lvalue to rvalue implicit
conversion which is used whenever needed.  There is a standard rvalue
to non-modifiable lvalue implicit conversion which is used whenever
needed.  There is a standard rvalue to modifiable lvalue explicit
conversion which may use whenever you like with user defined types.
The poor fundamental types are broken.

   int() = int();

Lvalue required.  We need to use the more complex version to work with
fundamental types.

   const_cast<int&>(static_cast<int const&>(int())) = 42;

Be sure to wear your bullet proof shoes.

John

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
John
11/9/2003 10:52:44 PM
> 
> Lvalue required.  We need to use the more complex version to work with
> fundamental types.
> 
>    const_cast<int&>(static_cast<int const&>(int())) = 42;
> 
Yup ;)

Note: I only said it adds a funny twist, I didn't say I have anything
against it. The example I've shown is perfectly ok, and works as
expected.

The reason I've posted is is because usually people (including me;) )
think of rvalue as "what can only be on the right side of operator="
(while, as I've shown, it's not true).

Best,
John

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
jtorjo
11/10/2003 10:53:23 AM
John Torjo wrote:
 > Consider the following example:
 >
 > struct Test {
 >     const Test& operator=( const Test &) const{
 >         return *this;
 >     }
 > };
 >
 > int main(int argc, char* argv[])
 > {
 >     Test() = Test();
 >       return 0;
 > }
 >
 > This adds a funny twist to the meaning lvalue, because in this case
 > every rvalue is an lvalue as well ;)
 > ...

I don't see what makes you to come to that conclusion.

The fact that you can place a temporary object on the left-hand side of
the assignment operator? But that's not how the term 'lvalue' is defined.

The fact that the standard requires lvalue on the left-hand side of
built-in assignment operators? But that only applies to _built-in_
assignment operators. There's no such requirement for user-defined
assignment operator.

-- 
Best regards,
Andrey Tarasevich


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Andrey
11/10/2003 1:28:09 PM
John Torjo <jtorjo@yahoo.com> schrieb in im Newsbeitrag:
c638aac5.0311082333.375479aa@posting.google.com...
> Hi all,
>
> Consider the following example:
>
> struct Test {
>     const Test& operator=( const Test &) const{
>         return *this;
>     }
> };
>
> int main(int argc, char* argv[])
> {
>     Test() = Test();
> return 0;
> }
>
> This adds a funny twist to the meaning lvalue, because in this case
> every rvalue is an lvalue as well ;)
>

Maybe you are mixing up operator semantics with function call semantics. You
example basically calls

Test().operator=( Test() );

which is actually not a 'real' assignment but a function call. It's possible
to call a function on an rvalue.

Best regards,

Matthias




      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Matthias
11/10/2003 7:48:18 PM
John Potter <jpotter@falcon.lhup.edu> schrieb in im Newsbeitrag:
qktsqvga4cge0d3koj8951f72597m6dem1@4ax.com...
> On 9 Nov 2003 09:21:28 -0500, jtorjo@yahoo.com (John Torjo) wrote:
>
> [snipping rxample]
>
> What's the problem?  There is a standard lvalue to rvalue implicit
> conversion which is used whenever needed.  There is a standard rvalue
> to non-modifiable lvalue implicit conversion which is used whenever
> needed.  There is a standard rvalue to modifiable lvalue explicit
> conversion which may use whenever you like with user defined types.
> The poor fundamental types are broken.
>
>    int() = int();
>
> Lvalue required.  We need to use the more complex version to work with
> fundamental types.
>
>    const_cast<int&>(static_cast<int const&>(int())) = 42;
>
> Be sure to wear your bullet proof shoes.
>

These rvalue to lvalue conversions have always confused me - could you give
a brief explanation and what it has to do with the "Test() = Test()"
example?

Best regards,

Matthias Hofmann




      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Matthias
11/10/2003 7:56:18 PM
R.F. Pels wrote:
<snip> 
> If you look at the title, the document pointed to is ancient, mostly
> C-related, but still instructive...
> 
>         http://members.home.nl/r.f.pels/articles/misc/rlvalue.txt

You do not appear to have understood the terminology yourself when you
wrote it.  Rvalues and lvalues are kinds of expression, not attributes
of variables.  Furthermore, you seem to have their meanings the wrong
way round.  An rvalue yields a value whereas an lvalue yields a
reference to (at the machine level, an address of) an object or
function.

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Ben
11/11/2003 10:08:43 AM
On 10 Nov 2003 14:56:18 -0500, "Matthias Hofmann"
<hofmann@anvil-soft.com> wrote:

 > John Potter <jpotter@falcon.lhup.edu> schrieb in im Newsbeitrag:
 > qktsqvga4cge0d3koj8951f72597m6dem1@4ax.com...

 > > What's the problem?  There is a standard lvalue to rvalue implicit
 > > conversion which is used whenever needed.  There is a standard rvalue
 > > to non-modifiable lvalue implicit conversion which is used whenever
 > > needed.  There is a standard rvalue to modifiable lvalue explicit
 > > conversion which may use whenever you like with user defined types.
 > > The poor fundamental types are broken.

 > >    int() = int();

 > > Lvalue required.  We need to use the more complex version to work with
 > > fundamental types.

 > >    const_cast<int&>(static_cast<int const&>(int())) = 42;

 > > Be sure to wear your bullet proof shoes.

 > These rvalue to lvalue conversions have always confused me - could you give
 > a brief explanation and what it has to do with the "Test() = Test()"
 > example?

int const& r(42);

In this, 42 is an rvalue and r is an unmodifiable lvalue.  It is allowed
to convert an rvalue to an unmodifiable lvalue by binding an rvalue to
a reference to const.  All references are lvalues.  Not all lvalues are
references say the language lawyers.

Since the above initialization of r is allowed, the static_cast of the
rvalue int() (a cute typed name for 0) is also allowed.  Now that we
have an lvalue, we can remove const with an lvalue const_cast and assign
to the thing which is about to self destruct.

In Test() = Test(), the left hand side is an rvalue, but operator= is a
member function which may be called on rvalues.  We still self destruct
both things.

An example of where these silly things are really useful is a class with
non-member operations which have side effects.

    ofstream("log.file", ios::app) << 42;

Works fine because <<(int) is a member function.

    ofstream("log.file", ios::app) << "Does not work";

Is an error because <<(ostream&, char*) is a non-member and an
rvalue may not be bound to a non-const reference.

    ofstream("log.file", ios::app).flush() << "Works fine";

This works because flush is a member function which may be called on an
rvalue and returns an lvalue which can be passed to the operator<<.

Rvalue to lvalue conversion are mostly amusing results of non-const
members being callable on rvalues.  In the above example, operator=
for streams is private and flush is public.  In both cases, the member
returns a reference which is an lvalue.

Now seeing your other post, this may also be useful.  In the case of
Test() = Test(), the simple call a function on an rvalue was used as
you said.  The non-standard return of operator= as Test const& still
converts an rvalue to an lvalue.

   (Test() = Test()) = Test();

This is invalid because it requires a modifiable lvalue and the
Test::operator= returned a non-modifiable lvalue.  We can "fix"
this as we did with int but in only one step since we have an
lvalue.

    const_cast<Test&>(Test() = Test()) = Test();

John

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
John
11/11/2003 4:50:43 PM
John Potter <jpotter@falcon.lhup.edu> schrieb in im Newsbeitrag:
06c0rvockqp7n1kvhld9h5a733fmtf0j02@4ax.com...
> On 10 Nov 2003 14:56:18 -0500, "Matthias Hofmann"
> <hofmann@anvil-soft.com> wrote:
>

[snip]

>
> Now seeing your other post, this may also be useful.  In the case of
> Test() = Test(), the simple call a function on an rvalue was used as
> you said.  The non-standard return of operator= as Test const& still
> converts an rvalue to an lvalue.
>
>    (Test() = Test()) = Test();
>
> This is invalid because it requires a modifiable lvalue and the
> Test::operator= returned a non-modifiable lvalue.  We can "fix"
> this as we did with int but in only one step since we have an
> lvalue.
>
>     const_cast<Test&>(Test() = Test()) = Test();
>

Thank you for the detailed explanation! One thing that puzzles me now is
your last example:

(Test() = Test()) = Test();

As you said, Test::operator=() returns a const reference - however, it also
declares operator=() to be a constant member function. Therefore, I wonder
if it is possible to call a constant member function on a non-modifiable
lvalue, so the above assignment should not be an error? This is the
definition of Test from the original post:

struct Test {
    const Test& operator=( const Test &) const{
        return *this;
    }
};

Best regards,

Matthias




      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Matthias
11/12/2003 8:30:05 PM
On 12 Nov 2003 15:30:05 -0500, "Matthias Hofmann"
<hofmann@anvil-soft.com> wrote:

> (Test() = Test()) = Test();

> As you said, Test::operator=() returns a const reference - however, it also
> declares operator=() to be a constant member function. Therefore, I wonder
> if it is possible to call a constant member function on a non-modifiable
> lvalue, so the above assignment should not be an error? This is the
> definition of Test from the original post:

> struct Test {
>     const Test& operator=( const Test &) const{
>         return *this;
>     }
> };

Right.  I missed the fact than all Test objects are const because they
have no state.  Maybe not the best example to talk about these things.
However, many function objects are of this form.  We usually do not
bother to define the operator= and take the compiler default.

John

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
John
11/14/2003 10:34:04 AM
Reply: