By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
432,046 Members | 2,058 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 432,046 IT Pros & Developers. It's quick & easy.

lvalue rvalue

P: n/a
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 to it.
This suggests that its non-const first of all, and secondly that it's an
lvalue. But now, see my last line of code, take away the // commenters. It
won't compile. You can assign to a temporary, yet it can't act as a
double&?! What the hell is going on?

-JKop
Jul 22 '05 #1
Share this Question
Share on Google+
11 Replies


P: n/a
JKop wrote:
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();

The above line does this: Chocolate2() returns a temporary
DoubleInDisguise object which is then assigned the value of the
temporary on the right (which is initialised to 0).


// Manipulate( Chocolate2() );


The above takes a double as an argument while you are passing it a
DoubleInDisguise.


Regards,

Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #2

P: n/a
Ioannis Vranos wrote:
JKop wrote:
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();


The above line does this: Chocolate2() returns a temporary
DoubleInDisguise object which is then assigned the value of the
temporary on the right (which is initialised to 0).


// Manipulate( Chocolate2() );


The above is passing to the void Manipulate(DoubleInDisguise&) a
temporary of type DoubleInDisguise which is not allowed since it is
getting a reference. The only way you can do it is by making the function

inline void Manipulate(const DoubleInDisguise& input)
{
//input.data = 222.76;
}
that is with a const reference. I suggest you get and read TC++PL 3, you
will find much knowledge in this book.


Regards,

Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #3

P: n/a
JKop wrote:

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 to it.
This suggests that its non-const first of all, and secondly that it's an
lvalue.


[...]

No, it is an rvalue. Yes, for built-in types, you can only assign to an
lvalue. But since DoubleInDisguise is a user-defined type, it has a member
function operator = (semantically, anyway), which can be called on an rvalue.

To prevent this kind of confusion, you can change Chocolate2 to
DoubleInDisguise const Chocolate2() {...}

Denis
Jul 22 '05 #4

P: n/a
struct Foo
{
void DoSomething() {}
};

void DoSomethingWithFoo(Foo& foo)
{
foo.DoSomething();
}

int main()
{
//So in this context the temporary is non-const...
Foo().DoSomething();

//...but in this context the temporary is const?
DoSomethingWithFoo(Foo());

//Note that I can bind a reference to the original
//temporary by doing the following. Is this
//undefined behavior?
DoSomethingWithFoo(Foo().operator=(Foo()));

return 0;
}

Oh well.

Maybe grokking this is beyond me. Time to move on.
Jul 22 '05 #5

P: n/a
DaKoadMunky wrote:
struct Foo
{
void DoSomething() {}
};

void DoSomethingWithFoo(Foo& foo) [7]> { foo.DoSomething();
}

int main()
{
//So in this context the temporary is non-const...
Foo().DoSomething();

//...but in this context the temporary is const? [17]> DoSomethingWithFoo(Foo());
//Note that I can bind a reference to the original
//temporary by doing the following. Is this
//undefined behavior?
DoSomethingWithFoo(Foo().operator=(Foo()));

return 0;
}

Oh well.

Maybe grokking this is beyond me. Time to move on.

Executing: C:\Program Files\ConTEXT\ConExec.exe "c:\mingw\bin\g++.exe" -std=c++98 -pedantic-errors -Wall
-fexpensive-optimizations -O3 -ffloat-store -mcpu=pentiumpro "temp.cpp"
-o temp

temp.cpp: In function `int main()':
temp.cpp:17: error: could not convert `Foo()' to `Foo&'
temp.cpp:7: error: in passing argument 1 of `void DoSomethingWithFoo(Foo&)' Execution finished.



Regards,

Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #6

P: n/a
Using MSVC++.NET I also received an error, as expected, on line 17.

I did not get an error on line 7.

The online compiler at http://www.comeaucomputing.com/pcgi-bin/compiler.cgi set
for Windows XP generated the same results...error on line 17 and no error on
line 7.

Of course using compilers is the wrong way to determine what is legal and
illegal :)
Jul 22 '05 #7

P: n/a
JKop wrote:
...
int main()
{
//Manipulate( Chocolate1() );

Chocolate2() = DoubleInDisguise();

// Manipulate( Chocolate2() );
}
See how the return-value from Chocolate2() can have an assigment done to it.
This suggests that its non-const first of all, and secondly that it's an
lvalue.
No, it doesn't suggest that it's an lvalue. Only built-in assignment
operator requires an lvalue on it left-hand side. User-defined
assignment operators don't have this requirement.
But now, see my last line of code, take away the // commenters. It
won't compile. You can assign to a temporary, yet it can't act as a
double&?! What the hell is going on?


Non-constant references _cannot_ be bound to rvalues. Non-constant
methods _can_ be called on non-constant rvalue objects. There's certain
intuitive feeling of asymmetry here, but that's just the way it is in C++.

--
Best regards,
Andrey Tarasevich

Jul 22 '05 #8

P: n/a
DaKoadMunky wrote:
Using MSVC++.NET I also received an error, as expected, on line 17.

I did not get an error on line 7.

The online compiler at http://www.comeaucomputing.com/pcgi-bin/compiler.cgi set
for Windows XP generated the same results...error on line 17 and no error on
line 7.

Yes the first error was indicated in line 17 and then it mentions line 7
where there is the function declaration/definition itself.

Of course using compilers is the wrong way to determine what is legal and
illegal :)

Yes I did not use the compiler in my original post, but when I saw your
post with the "it works" attitude, I decided to use it in your code.
Temporaries are destroyed just after you pass them to a function,
including when the function is taking references, with the exception
when it takes const references as arguments. In the last case, the
temporary persists until it reaches the end of the function and this is
the way many standard library algorithms work.


Regards,

Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #9

P: n/a
On Fri, 16 Jul 2004 16:23:17 -0700, Ioannis Vranos wrote:
Temporaries are destroyed just after you pass them to a function,
They are destroyed at the end of the complete statement where they are
created. The complete statement may have many other function
calls. The destruction of the temporary must wait untill all of those
calls are completed.
including when the function is taking references, with the exception
when it takes const references as arguments.
We cannot pass temporaries to functions taking non-const references
anyway. So I will limit the rest of the discussion to functions that
take const references.
In the last case, the
temporary persists until it reaches the end of the function and this is
the way many standard library algorithms work.


This is incorrect. The temporary lives longer than the function call
as I described above. The destruction must wait until the statement
completes.

Here is a code that tries to demonstrates this:

class C
{
int i_;

public:
C(int i) : i_(i) { cout << "construct\n"; }
C(C const &) { cout << "copy\n"; }
C & operator=(C const &) { cout << "assign\n"; }
~C() { cout << "destroy\n"; }

void use() const {}
};

int foo(C const & c)
{
c.use();
cout << "foo\n";
return 0;
}

void bar(int, C const &)
{
cout << "bar\n";
}

C blah()
{
return 1;
}

int main()
{
bar(foo(blah()), C(0));
}

The two temporaries created must live until bar exits. The output of
the program must have two 'destroy's printed *after* 'bar'.

Ali
Jul 22 '05 #10

P: n/a
Ali Cehreli wrote:
They are destroyed at the end of the complete statement where they are
created. The complete statement may have many other function
calls. The destruction of the temporary must wait untill all of those
calls are completed.

This is incorrect. The temporary lives longer than the function call
as I described above. The destruction must wait until the statement
completes.

Yes you are right.


Regards,

Ioannis Vranos

http://www23.brinkster.com/noicys
Jul 22 '05 #11

P: n/a

I've just had a quick read over this thread.

We can summarize temporaries with the following:

non-const (they're *not* const)
r-value (they're *not* an l-value)

(strange how it is!)

With has the following repercussions (for want of a better word):

A temporary cannot be bound to a non-const reference ( not because it's
const, because it *isn't*, but because it's an r-value, ie. you can only
bind a non-const reference to an l-value ).

So, where you have:

AnyType& blah = Anything...

then "Anything" must be:

non-const
l-value
And where you have:

AnyType const & blah = Anything...

Then "Anything" can quite literally be anything!
-JKop
Jul 22 '05 #12

This discussion thread is closed

Replies have been disabled for this discussion.