rvalue or lvalue?

  • Permalink
  • submit to reddit
  • Email
  • Follow


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
Reply jtorjo 11/9/2003 2:21:28 PM

See related articles to this posting

> 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
Reply 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
Reply 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
Reply 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
Reply 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
Reply 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
Reply 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
Reply 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
Reply 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
Reply 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
Reply 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
Reply John 11/14/2003 10:34:04 AM
comp.lang.c++.moderated 10585 articles. 6 followers. Post

11 Replies
167 Views

Similar Articles

[PageSpeed] 22


  • Permalink
  • submit to reddit
  • Email
  • Follow


Reply:

Similar Artilces:

operators requiring lvalue/rvalue operands and resulting in rvalue/lvalue
These were the questions asked to me by my friend 1. Operator which may require an lvalue operand, yet yield an rvalue. 2. Operator which may require an rvalue operand, yet yield an lvalue. My answer to these questions are & and * respectively. Is/Are there any other operator(s) satisfying these criteria? Kavya wrote: > These were the questions asked to me by my friend > > 1. Operator which may require an lvalue operand, yet yield an rvalue. > 2. Operator which may require an rvalue operand, yet yield an lvalue. > > My answer to these questions are & and * re...

Lvalue-to-rvalue conversion vs rvalue reference
Hi, 3.10/7 in N3000 Says: "Whenever an lvalue appears in a context where an rvalue is expected, the lvalue is converted to an rvalue;" On the other hand I was pretty sure that the following code shouldn't compile: void possiblyDestroy( Obj && obj ); int main() { Obj obj; possiblyDestroy( obj ); } In the function call above, an rvalue is expected, "obj" is an lvalue, so it "appears in a context where an rvalue is expected". Is the above code valid? Regards, &rzej -- [ comp.std.c++ is moderated. To subm...

lvalues and rvalues
Hello, I am quite confused about this, so I split it in to subquestions, here we go: 1. Is an lvalue the expression itself, or is it the result yielded by evaluation of an expression? Take this for example: int i = 10; int *p = &i; and then dereference: *p; is the expression "*p" the thing you call an lvalue or is an lvalue the result yielded by evaluating that lvalue-expression? 2. Rvalues, is rvalues the result yielded by an rvalue-expression, or is it the expression itself? If its the result yielded by evaluation of an rvalue-expression is an rvalue a plain val...

lvalue rvalue
The following compiles: // syrup.cpp struct DoubleInDisguise { double data; }; double Chocolate1() { double blah = 67.22; return blah; } DoubleInDisguise Chocolate2() { DoubleInDisguise blah = { 67.22 }; return blah; } /* inline void Manipulate(double& input) { input = 222.76; } */ inline void Manipulate(DoubleInDisguise& input) { //input.data = 222.76; } int main() { //Manipulate( Chocolate1() ); Chocolate2() = DoubleInDisguise(); // Manipulate( Chocolate2() ); } See how the return-value from Chocolate2() can have an assigment done ...

Template rvalue reference binds to an lvalue, but ordinary rvalue reference does not
Hello Group! As I understand it, an rvalue reference is not allowed to bind to an lvalue, and I see this behavior in simple test cases. But when the rvalue reference is part of a template, it can. Specifically: void f (int&& arg) {} template<typename T> void g (T&& arg) {} void h() { int i; f (i); // fails -- error: cannot bind 'int' lvalue to 'int&&' g (i); // succeeds } (To be clear, the line "g (i);" compiles, but "f (i);" does not.) Why does the rvalue-reference argument in...

lvalue and rvalue?
int x; x = 10; here x is the lvalue (the object holding a value) and 10 is the rvalue (the value being assigned to an object) correct? zach Zach wrote: > int x; > x = 10; > > here x is the lvalue (the object holding a value) and 10 is the rvalue > (the value being assigned to an object) correct? That's true. In K&R-2 it is stated that "An object is a named region of storage; an lvalue is an expression referring to an object". So in your example, 'x' is the expression and 10 the actual object. An exception to this are arrays, since the name of an ...

lvalue/rvalue?
I've alway thought lvalue means Left Value and rvalue means Right Value before i've read someone's article. It is said "lvalue = location value" and "rvalue = read value". Which one is right, then? On 2007-07-15 15:24, Yarco wrote: > I've alway thought lvalue means Left Value and rvalue means Right > Value before i've read someone's article. > It is said "lvalue = location value" and "rvalue = read value". > Which one is right, then? I don't think it's ever specified in the standard what l and r stands for,...

rvalues and lvalues
How do I write a function that will accept both rvalues and lvalues? For example, if I write this (contrived example): #include <iostream> #include <vector> std::vector<int> & operator << (std::vector<int> & x, const std::vector<int>::value_type & y) { x.push_back(y); return x; } int main() { std::cout << (std::vector<int>() << 1)[0] << std::endl; } Then I get: Dynamo.cpp: In function 'int main()': Dynamo.cpp:12:41: error: no match for 'operator<<' in 'std::vecto...

Defect Report: lvalue-to-rvalue conversion incorrectly doesn't apply to rvalue arrays
5[expr]/8 contains the following wording Whenever an lvalue expression appears as an operand of an operator that expects an rvalue 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 an rvalue. This won't cause the conversion for rvalue arrays. Testcase that i believe is currently rejected by the standards wording (but should be accepted): struct A { int n[1]; }; A f() { return A(); } int main() { f().n[0] = 0; } -- [ comp.std.c++ is moderated. To submit arti...