469,646 Members | 1,100 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,646 developers. It's quick & easy.

tricky stringstream-based temporary

Hi folks,
I have trouble writing a class, derving from stringstream, that collects
item and once it's done will write them to std::cout in one go. It works
fine except when I use it as a temporary. Here is a tiny test programm:

#include <iostream>
#include <sstream>

class Gatherer : public std::stringstream {
public:

~Gatherer ( void ) {
std::cout << this->str() << std::endl;
}

};

int main ( void ) {
{
Gatherer() << "hello world!";
}
{
Gatherer gather;
gather << "hello world!";
}
{
Gatherer() << std::dec << "hello world!";
}
}
On my machine, it prints:

0x8049e48
hello world!
hello world!

So, clearly the first line is an address. I have no explanation for this. I
am especially puzzled by the third line. Inserting a std::dec should not
have this effect, or should it?
Best regards

Kai-Uwe
Jul 22 '05 #1
19 2162
"Kai-Uwe Bux" <jk********@gmx.net> wrote...
I have trouble writing a class, derving from stringstream, that collects
item and once it's done will write them to std::cout in one go. It works
fine except when I use it as a temporary. Here is a tiny test programm:

#include <iostream>
#include <sstream>

class Gatherer : public std::stringstream {
public:

~Gatherer ( void ) {
std::cout << this->str() << std::endl;
}

};

int main ( void ) {
{
Gatherer() << "hello world!";
}
{
Gatherer gather;
gather << "hello world!";
}
{
Gatherer() << std::dec << "hello world!";
}
}
On my machine, it prints:

0x8049e48
hello world!
hello world!

So, clearly the first line is an address. I have no explanation for this. I am especially puzzled by the third line. Inserting a std::dec should not
have this effect, or should it?


I think you're running into synchronisation problem. When compiled
with Intel v4.5 or VC++ v6sp5, this code outputs three hello. When
compiled with VC++ v7.1, it prints an address first and then two
hello, just like you described.

I think what you get is that by the time the destructor is executing,
all bets are off WRT the contents of this->str(), it may not contain
anything, or return a valid object... You might be incurring the UB.
Just a guess.

Victor
Jul 22 '05 #2
Victor Bazarov wrote:
"Kai-Uwe Bux" <jk********@gmx.net> wrote...
I have trouble writing a class, derving from stringstream, that collects
item and once it's done will write them to std::cout in one go. It works
fine except when I use it as a temporary. Here is a tiny test programm:

#include <iostream>
#include <sstream>

class Gatherer : public std::stringstream {
public:

~Gatherer ( void ) {
std::cout << this->str() << std::endl;
}

};

int main ( void ) {
{
Gatherer() << "hello world!";
}
{
Gatherer gather;
gather << "hello world!";
}
{
Gatherer() << std::dec << "hello world!";
}
}
On my machine, it prints:

0x8049e48
hello world!
hello world!

So, clearly the first line is an address. I have no explanation for this.

I
am especially puzzled by the third line. Inserting a std::dec should not
have this effect, or should it?


I think you're running into synchronisation problem. When compiled
with Intel v4.5 or VC++ v6sp5, this code outputs three hello. When
compiled with VC++ v7.1, it prints an address first and then two
hello, just like you described.

I think what you get is that by the time the destructor is executing,
all bets are off WRT the contents of this->str(), it may not contain
anything, or return a valid object... You might be incurring the UB.
Just a guess.

Victor


Thanks for your help.

I eliminated inheritance as a possible source of the problem:

#include <fstream>

int main ( void ) {
std::ofstream( "greeting.out" ) << "hello world!\n";
}
This compiles fine. But it does unexpected things (well, as of now, I
actually was expecting this):

news_group> cat greeting.out
0x8048a01news_group>
So the problem definitely lies in the fact that a temporary is created.
Does the standard say that temporary streams have undefined behaviour? I
was under the impression that a temporary is supposed to behave exactly
like the real thing except that for its life time there are only very few
guarantees (like it will live at least to see the completion of the
expression of which it is a part).

As of now, I am considering the possibility that it could be a bug in my
standard library.
Thanks again

Kai-Uwe

Jul 22 '05 #3
Kai-Uwe Bux wrote:

int main ( void ) {
{
Gatherer() << "hello world!";
}
{
Gatherer gather;
gather << "hello world!";
}
{
Gatherer() << std::dec << "hello world!";
}
}


You're not supposed to pass a temporary for a non-const reference
parameter (in this case, the first parameter of operator<<). The result
of doing so is undefined.

--
Russell Hanneken
eu*******@cbobk.pbz
Use ROT13 to decode my email address.
Jul 22 '05 #4
Russell Hanneken wrote:
Kai-Uwe Bux wrote:

int main ( void ) {
{
Gatherer() << "hello world!";
}
{
Gatherer gather;
gather << "hello world!";
}
{
Gatherer() << std::dec << "hello world!";
}
}


You're not supposed to pass a temporary for a non-const reference
parameter (in this case, the first parameter of operator<<). The result
of doing so is undefined.


First off all: thank you. I was really puzzled.

Second: Could you direct me to the point in the standard where I find this.
I was just reading 12.2.5:

.... A temporary bound to a reference parameter in a function call (5.2.2)
persists until the completion of the full expression containing the call.
....

Wouldn't that have been a great place to put in a warnig? Please do not
get me wrong, I do not doubt that you are right -- I am just curious.
Thanks again

Kai-Uwe
Jul 22 '05 #5
Kai-Uwe Bux wrote:
{
Gatherer() << "hello world!";
}
Some background:

(1) When you call a function f(T()) then the function signature must be
either f(T) or f(const T&) but not f(T&). In other words, if the signature
is f(T&) then the argument cannot be a temporary.

(2) When you call a function T().f() then the function signature of T::f may
be either T::f() const or T::f(). In other words, you can call a non-const
member function on a temporary. This is a contrast to (1).

The reason my you see a number is that because of

Gatherer() <<

the compiler spots a temporary, and looks for member overloads
Gatherer::operator<< that match the function arguments. Now operator<<
const void* is implemented as a member, but operator<< const char * is
implemented as a non-member.

So while we wish the code calls

std::ostream<char>& std::operator<<(ostream&, const char *);

it really calls only std::ostream::operator<<(const void *);

As a QoI, a good compiler would probably look for both members and
non-members to call, and if it finds the non-member function is the right
one to call, issue an error or warning that the first argument cannot be a
temporary -- or at least issue an ambiguity between the two possible
operator<< to call.

So what you're seeing is the address of "hello world!". Try const char * s
= "hello world!" and then Gatherer() << s, followed by cout << (const void
*)(s), and see what happens
{
Gatherer gather;
gather << "hello world!";
}
Works as expected.
{
Gatherer() << std::dec << "hello world!";
}
}
Also works as expected. Fortunately Gatherer() << std::dec calls a member
function

basic_ostream::operator<<(ios_base& (*)(ios_base&))

and for member functions you are allowed to call non-const member functions
on a temporary. So this sets the decimal mode, returns an ostream&, adds
text to the ostream, and finally destroys the object and it prints what it
should.
You're not supposed to pass a temporary for a non-const reference
parameter (in this case, the first parameter of operator<<). The result
of doing so is undefined.


Right, but for the last case it's fine.
To the original problem, a possible solution is

class Gatherer : public std::stringstream {
public:

~Gatherer ( void ) {
std::cout << d_stream.str() << std::endl;
}
template <class T>
Gatherer& operator<<(const T&);

private:
std::stringstream d_stream;
};
Jul 22 '05 #6
"Victor Bazarov" <v.********@comAcast.net> wrote in message news:QX7yc.2123
I think you're running into synchronisation problem. When compiled
with Intel v4.5 or VC++ v6sp5, this code outputs three hello. When
compiled with VC++ v7.1, it prints an address first and then two
hello, just like you described.


MSVC7is more right than Intel or MSVC7. The compiler should never call the
non-member. The ideal compiler would give an error/warning.
Jul 22 '05 #7
Kai-Uwe Bux wrote:
Russell Hanneken wrote:

You're not supposed to pass a temporary for a non-const reference
parameter (in this case, the first parameter of operator<<). The result
of doing so is undefined.


Could you direct me to the point in the standard where I find this.


I couldn't find a place where it's stated directly. I think it's more
an implication of 8.5.3, section 5, which lists the valid ways to
initialize a reference. Temporaries just don't meet the qualifications
to be an initializer for a non-const reference.

Bjarne Stroustrup puts it pretty bluntly on page 98 of _The C++
Programming Language_: "The initializer for a 'plain' T& must be an
lvalue of type T."

--
Russell Hanneken
eu*******@cbobk.pbz
Use ROT13 to decode my email address.
Jul 22 '05 #8
Hi,
Thank you very much for this detailed explanation. Walking me through
the problem like that was more than I could have hoped for.
Best

Kai-Uwe
Jul 22 '05 #9
Siemel Naran wrote:
Gatherer() << std::dec << "hello world!";


Also works as expected. Fortunately Gatherer() << std::dec calls a member
function

basic_ostream::operator<<(ios_base& (*)(ios_base&))

and for member functions you are allowed to call non-const member functions
on a temporary. So this sets the decimal mode, returns an ostream&, adds
text to the ostream, and finally destroys the object and it prints what it
should.
You're not supposed to pass a temporary for a non-const reference
parameter (in this case, the first parameter of operator<<). The result
of doing so is undefined.


Right, but for the last case it's fine.


I don't follow this. The result of

Gatherer() << std::dec

is a reference to a temporary. So

(result of first expression) << "hello world!"

is an attempt to initialize a non-const reference parameter with a
temporary, which is still a problem, right?

--
Russell Hanneken
eu*******@cbobk.pbz
Use ROT13 to decode my email address.
Jul 22 '05 #10
On Fri, 11 Jun 2004 16:35:16 GMT, Russell Hanneken <me@privacy.net>
wrote:
Siemel Naran wrote:
Gatherer() << std::dec << "hello world!";


Also works as expected. Fortunately Gatherer() << std::dec calls a member
function

basic_ostream::operator<<(ios_base& (*)(ios_base&))

and for member functions you are allowed to call non-const member functions
on a temporary. So this sets the decimal mode, returns an ostream&, adds
text to the ostream, and finally destroys the object and it prints what it
should.
You're not supposed to pass a temporary for a non-const reference
parameter (in this case, the first parameter of operator<<). The result
of doing so is undefined.


Right, but for the last case it's fine.


I don't follow this. The result of

Gatherer() << std::dec

is a reference to a temporary. So

(result of first expression) << "hello world!"

is an attempt to initialize a non-const reference parameter with a
temporary, which is still a problem, right?


No. (result of first expression) is a std::ostream& that happens to
reference a temporary. You can bind a std::ostream& to a std::ostream&
no problem.

Don't forget that the temporary lasts until the end of the full
expression, usually the ;

Tom
--
C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Jul 22 '05 #11
tom_usenet wrote:
On Fri, 11 Jun 2004 16:35:16 GMT, Russell Hanneken <me@privacy.net>
wrote:
Siemel Naran wrote:

Gatherer() << std::dec << "hello world!";

Also works as expected. Fortunately Gatherer() << std::dec calls a
member function

basic_ostream::operator<<(ios_base& (*)(ios_base&))

and for member functions you are allowed to call non-const member
functions
on a temporary. So this sets the decimal mode, returns an ostream&,
adds text to the ostream, and finally destroys the object and it prints
what it should.

You're not supposed to pass a temporary for a non-const reference
parameter (in this case, the first parameter of operator<<). The result
of doing so is undefined.

Right, but for the last case it's fine.


I don't follow this. The result of

Gatherer() << std::dec

is a reference to a temporary. So

(result of first expression) << "hello world!"

is an attempt to initialize a non-const reference parameter with a
temporary, which is still a problem, right?


No. (result of first expression) is a std::ostream& that happens to
reference a temporary. You can bind a std::ostream& to a std::ostream&
no problem.

Don't forget that the temporary lasts until the end of the full
expression, usually the ;

Tom


Thanks to all of you. This is getting really interesting, and I have to
wonder why C++ is imposing this restriction. Consider:
#include <iostream>
#include <sstream>

class Gatherer : public std::stringstream {
public:

~Gatherer ( void ) {
std::cout << this->str() << std::endl;
}

void insert ( const std::string & str ) {
*this << str;
}

Gatherer& me ( void ) {
return( *this );
}
};

static
void insert ( Gatherer & gather, const std::string str ) {
gather.insert( str );
}

int main ( void ) {
insert( Gatherer(), std::string( "hello world!" ); // error
insert( Gatherer().me(), std::string( "hello world!" ) ); // sound
}

From what I read in this thread, the second line should be sound because
(a) I am allowed to call a non-const method of a temporary and (b) this
method returns a reference that just happens to be bound to a temporary and
therefore can be used to initialized the non-const & parameter in insert.
Boy, what surprises C++ has to offer once you scratch a little bit on the
surface.

I have learned now that 8.5.3.5 is at the heart of the matter. It states
that a reference is to be initialized by an lvalue or by a const
non-volatile expression. Now there are two questions left:

1) When the standard says that a program shall initialize references
according to the rules in 8.5.3.5, does this mean that if a program fails
to do so, we have undefined behaviour or does this count as a "diagnosable
semantic rule" so that a compliant compiler will have to tell me.

2) What is the rational for the rules in 8.5.3.5 in the first place. If
they can be circumvented like above, they seem not to offer protection in
the first place.
Thanks again for all the explanations.
Best

Kai-Uwe

Jul 22 '05 #12
tom_usenet wrote:

No. (result of first expression) is a std::ostream& that happens to
reference a temporary. You can bind a std::ostream& to a std::ostream&
no problem.


But the reference is still to a temporary object. A temporary object isn't
an lvalue, right? And doesn't a non-const reference have to be initialized
by an lvalue?

--
Russell Hanneken
eu*******@cbobk.pbz
Use ROT13 to decode my email address.
Jul 22 '05 #13
Russell Hanneken wrote:
tom_usenet wrote:

No. (result of first expression) is a std::ostream& that happens to
reference a temporary. You can bind a std::ostream& to a std::ostream&
no problem.


But the reference is still to a temporary object. A temporary object
isn't
an lvalue, right? And doesn't a non-const reference have to be
initialized by an lvalue?


From the standard 3.10.5:

The result of calling a function that does not return a reference is an
rvalue. User defined operators are functions, and whether such operators
expect or yield lvalues is determined by their parameter and return types.
Unfortunately, this does not tell us the precise rules how the parameter
and return typed determine whether the result is an lvalue. However it
seems to imply that it shall not matter whether the object whose member
fucntion is called is a temporary--that would not show in the parameter and
return types.
Best

Kai-Uwe
Jul 22 '05 #14
Hi everybody,
First I would like to thank everybody participating in this thread:
I learned a lot.

Out of pure curiosity, I whipped up some code that sums up the
understanding of the situation that I have as of now. I would like
to solicity any kind of criticism / code review. In particular, I
would like to know if my reasoning for correctness of the code is
flawed.
Thanks again

Kai-Uwe

// How to pass a temporary to a non-const reference
// ================================================

// ============================================
// | Description |
// ============================================
/*
| This defines the template l_ctor<T> which promotes
| constructors for T to effectively yield lvalues.
|
| A constructor call T() [ T(a), T(a,b), ... ] will
| create a temporary object of type T. This cannot by
| itself be used as an lvalue. In particular, it is not
| suitable to initialize a T& parameter in a function call.
| Sometimes, this might be a nuisance.
|
| The constructor l_ctor<T() [ l_ctor<T>(a),
| l_ctor<T>(a,b), ... ] promotes the underlying
| constructor T() so that it actually yields a
| something that at least can be converted to an
| lvalue and thus used to initialize a T&.
*/

// ============================================
// | Implementation |
// ============================================

// The template class l_ctor<T>
// ----------------------------
/*
| We use reversed inheritance.
| I just learned this two days ago through an introduction
| to templates that was criticized on this news group.
| I have to admit, I was not sure whether reversed inherticance
| could be useful.
*/
template < typename T >
class l_ctor : public T {
public:

l_ctor ( void ) :
T ()
{}

template < typename A >
l_ctor ( A a ) :
T ( a )
{}

template < typename A, typename B >
l_ctor ( A a, B b ) :
T ( a, b )
{}

template < typename A, typename B, typename C >
l_ctor ( A a, B b, C c ) :
T ( a, b, c )
{}

template < typename A, typename B, typename C,
typename D >
l_ctor ( A a, B b, C c, D d ) :
T ( a, b, c, d )
{}

template < typename A, typename B, typename C,
typename D, typename E >
l_ctor ( A a, B b, C c, D d, E e ) :
T ( a, b, c, d, e )
{}

template < typename A, typename B, typename C,
typename D, typename E, typename F >
l_ctor ( A a, B b, C c, D d, E e, F f ) :
T ( a, b, c, d, e, f )
{}

// Now we add a feature [maybe a bug]:
// This class can be converted to T&:
operator T& ( void ) {
return( *this );
}

}; // l_ctor<T>
// ===========================================
// | How and why it works: |
// ===========================================
/*
| In calling l_ctor<T>() a temporary onject of type l_ctor<T>
| is created. The templated constructor invokes T() to initialize
| the temporary. This temporary is convertible to T&, which would
| be an lvalue. Thus, this object satisfies the requirements of
| 8.5.3.5 and can be used to initialize a T&.
*/
// ===========================================
// | Example |
// ===========================================

#include <iostream>
#include <string>

void write ( std::ostream & out, std::string line ) {
out << line;
}

int main ( void ) {
write( l_ctor<std::ostream>( std::cout.rdbuf() ), "hello world!\n" );
}

// end of story
Jul 22 '05 #15
"Russell Hanneken" <me@privacy.net> wrote in message news:8blyc.10340
I don't follow this. The result of

Gatherer() << std::dec

is a reference to a temporary. So
Yes, it is a reference to a temporary, but the standard allows it just
because this version of operator<< happens to be a member function. Also,
the standard requires the compiler only destroy the temporary object at the
end of the statement or the semicolon (unless it can prove that destructing
the object earlier won't have side effects, the as-if rule).

So now that you've returned the temporary, you're free to use in any
operator<<, whether it is a member or non-member function. The invocation
of the second operator<< doesn't itself create a temporary, but instead it
uses the reference returned by the first operator<<, so this second
operator<< can be a member or non-member function.
(result of first expression) << "hello world!"
The whole thing is

operator<<(operator<<(Gatherer(), std::dec), "hello world!");

As written, the inner operator<< is illegal because you pass a temporary by
non-const reference. But because this particular operator<< happens to be a
member function, the compiler must suppress the error message.

So then it does create a temporary, which it will destroy at the semicolon,
after completing the second outer operator<<.

And so the inner operator<< basically returns a reference to this temporary.

But to the outer operator<< all you have is a reference to an existing
ostream (which happens to be a temporary). But it does not care about
whether the original object was a temporary or not. So it goes ahead and
uses the reference to non-const ostream& in the call to print "hello
world!".

It seems like a flaw in the language that you can get different behavior
depending on whether the overloaded operator is a member or non-member.
It's only because of the mix between operator overloading, license to use
members or non-members, and function overloading -- ie. you can overload
operator<< either as a member or non-member, and then have different
operator<< for different arguments. Maybe a good compiler will compensate
for the flaw by throwing a warning message.

is an attempt to initialize a non-const reference parameter with a
temporary, which is still a problem, right?

Jul 22 '05 #16
Siemel Naran wrote:
"Russell Hanneken" <me@privacy.net> wrote in message news:8blyc.10340
I don't follow this. The result of

Gatherer() << std::dec

is a reference to a temporary. So
Yes, it is a reference to a temporary, but the standard allows it just
because this version of operator<< happens to be a member function.


You seem to think I'm saying that

Gatherer()

results in a temporary, and that I have a problem with the result being
used as the left operand in the above << operation. No, I'm saying that

Gatherer() << std::dec

results in a reference to a temporary object, and I have a problem with
that result being used in the larger << operation.
the standard requires the compiler only destroy the temporary object at the
end of the statement or the semicolon (unless it can prove that destructing
the object earlier won't have side effects, the as-if rule).
This is neither here nor there. We all agree that this statement

Gatherer() << "hello world!";

is bad, despite the fact that the temporary object produced by
Gatherer() exists until the end of the statement.
So now that you've returned the temporary, you're free to use in any
operator<<, whether it is a member or non-member function. The invocation
of the second operator<< doesn't itself create a temporary, but instead it
uses the reference returned by the first operator<<, so this second
operator<< can be a member or non-member function.
This is exactly the point I don't see. Where does the standard say
that? What difference does it make whether the temporary object comes
directly from

Gatherer()

or comes indirectly from

Gatherer() << std::dec

? It's the same temporary object. And as far as I know, it's illegal
to use temporary objects to initialize non-const references. A
temporary object isn't an lvalue.
operator<<(operator<<(Gatherer(), std::dec), "hello world!");
[. . .]
And so the inner operator<< basically returns a reference to this temporary.

But to the outer operator<< all you have is a reference to an existing
ostream (which happens to be a temporary). But it does not care about
whether the original object was a temporary or not.


Why not?

--
Russell Hanneken
eu*******@cbobk.pbz
Use ROT13 to decode my email address.
Jul 22 '05 #17
"Russell Hanneken" <me@privacy.net> wrote in message
news:VH****************@newsread1.news.pas.earthli nk.net...
Siemel Naran wrote: This is exactly the point I don't see. Where does the standard say
that? What difference does it make whether the temporary object comes
directly from

Gatherer()

or comes indirectly from

Gatherer() << std::dec

? It's the same temporary object. And as far as I know, it's illegal
to use temporary objects to initialize non-const references. A
temporary object isn't an lvalue.


Good question. It's because the standard does not require the compiler to
analyze the origin of variables. In operator<<(Gatherer(),whatever) the
compiler can see the first argument is a temporary. In operator<<(something
that could perhaps be a temporary, whatever) the compiler does not know
whether the first argument is a temporary, because it does not analyze where
the object came from. It sounds strange, and it is.

With the analysis that you seem to propose, the compiler should analyze the
origin of the reference, to determine whether it really is a temporary.
This kind of analysis would be good for const_cast too. The compiler never
gives an error if you cast away const, but if it does analysis to determine
if the original object were declared const in the first place, then it could
give an error.

But consider this:

ostream& silly(ostream& o) {
o << "hello world!";
}

Gatherer() << silly; // works because this particular operator<< is a
non-member

Now in function silly the compiler is calling a non-member function
operator<<(ostream&, const char *) on a temporary. Yet it won't error out.
Pretty strange stuff!
Jul 22 '05 #18
On Fri, 11 Jun 2004 14:37:55 -0400, Kai-Uwe Bux <jk********@gmx.net>
wrote:
I have learned now that 8.5.3.5 is at the heart of the matter. It states
that a reference is to be initialized by an lvalue or by a const
non-volatile expression. Now there are two questions left:

1) When the standard says that a program shall initialize references
according to the rules in 8.5.3.5, does this mean that if a program fails
to do so, we have undefined behaviour or does this count as a "diagnosable
semantic rule" so that a compliant compiler will have to tell me.
"shall" generally refers to a diagnosable rule. Undefined behaviour is
explicitly indicated where appropriate.
2) What is the rational for the rules in 8.5.3.5 in the first place. If
they can be circumvented like above, they seem not to offer protection in
the first place.


It's to avoid accidental errors. e.g. if it were allowed:

void f(int& i)
{
i = 10;
}

float val;

f(val);
//val unchanged!

For classes you might get a similar problem with conversion functions.
e.g.

void f(std::string& s)
{
s = "Foo";
}

f("Hello"); //whoops

If you explicitly get hold of a non-const reference, then that's up to
you - you know what you're doing. You may find this useful:

template <class T>
T& rvalue_to_lvalue(T const& t)
{
return const_cast<T&>(t);
}

Obviously it must be used with care, and never called on a const
value.

The next C++ standard is considering a feature called "rvalue
references", which can bind to temporaries:

std::string&& s = get_temp_string();

They are useful for implementing "move semantics", and area where C++
is currently rather weak.

Tom
--
C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Jul 22 '05 #19
On Fri, 11 Jun 2004 19:44:25 GMT, "Russell Hanneken" <me@privacy.net>
wrote:
tom_usenet wrote:

No. (result of first expression) is a std::ostream& that happens to
reference a temporary. You can bind a std::ostream& to a std::ostream&
no problem.


But the reference is still to a temporary object. A temporary object isn't
an lvalue, right?


No, but a reference to one is. There are plenty of ways of forming an
lvalue from a temporary if you so wish. All the language forbids is
the direct binding of an rvalue to a non-const reference.

Tom
--
C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Jul 22 '05 #20

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

2 posts views Thread by Bill Beacom | last post: by
2 posts views Thread by Woodster | last post: by
3 posts views Thread by Mike Chirico | last post: by
1 post views Thread by KidLogik | last post: by
5 posts views Thread by cherico | last post: by
5 posts views Thread by William Payne | last post: by
9 posts views Thread by martinezfive | last post: by
4 posts views Thread by clb | last post: by
reply views Thread by gheharukoh7 | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.