Why extracting string from stringstream(a) fails?

M

Mc Lauren Series

#include <iostream>
#include <sstream>

using namespace std;

int main()
{
string a("test");
string b;
stringstream(a) >> b;
}

When I try to execute this code, I get errors:

foo.c: In function 'int main()':
foo.c:10: error: no match for 'operator>>' in
'std::basic_stringstream<char, std::char_traits<char>,
std::allocator<char> >(((const std::basic_string<char,
std::allocator<char> >&)((const said:
*)(& a))), std::eek:perator|(_S_out, _S_in)) >> b'

Why does this error occur? Isn't stringstream(a) supposed to behave
just like a stream? With cout I can extract string into a string
variable. Then why not here?
 
V

Victor Bazarov

Mc said:
#include <iostream>
#include <sstream>

using namespace std;

int main()
{
string a("test");
string b;
stringstream(a) >> b;
}

When I try to execute this code, I get errors:

foo.c: In function 'int main()':
foo.c:10: error: no match for 'operator>>' in
'std::basic_stringstream<char, std::char_traits<char>,
std::allocator<char> >(((const std::basic_string<char,


Why does this error occur? Isn't stringstream(a) supposed to behave
just like a stream? With cout I can extract string into a string
variable. Then why not here?

The operator >> is a non-member. It takes the first argument by a
non-const reference, which cannot be initialized with a temporary.
Define a named variable and you will be able to do what you want:

stringstream sa(a);
sa >> b;

There is a trick to overcome this particular limitation, but it's not
the best approach. You can do something like that

stringstream(a) >> boolalpha >> b;

which invokes a non-const member function (which is OK for temporaries)
and the function (that "outputs" a manipulator) returns a non-const
reference, which then can be passed to the non-member operator<<.

V
 
M

Mc Lauren Series

The operator >> is a non-member.  It takes the first argument by a
non-const reference, which cannot be initialized with a temporary.
Define a named variable and you will be able to do what you want:

     stringstream sa(a);
     sa >> b;

There is a trick to overcome this particular limitation, but it's not
the best approach.  You can do something like that

     stringstream(a) >> boolalpha >> b;

which invokes a non-const member function (which is OK for temporaries)
and the function (that "outputs" a manipulator) returns a non-const
reference, which then can be passed to the non-member operator<<.

V

If >> is a non-member, why does this work?

#include <iostream>
#include <sstream>
#include <string>

using namespace std;

int main()
{
string a("1234");
// string b;
int b;
stringstream(a) >> b;
cout << b << endl;
}


If we change the data type of b to int, the code works fine but not
with b as string. Why?
 
M

Maxim Yegorushkin

If>> is a non-member, why does this work?

Some stream operators are member functions, others are not. Member
functions can be called on temporary objects. boolalpha is handled by a
member function which returns std::istream&. That std::istream& can than
be accepted by both member and non-member operator>> functions.
#include<iostream>
#include<sstream>
#include<string>

using namespace std;

int main()
{
string a("1234");
// string b;
int b;
stringstream(a)>> b;
cout<< b<< endl;
}


If we change the data type of b to int, the code works fine but not
with b as string. Why?

Because extracting into an integer is handled by a member function of
std::istream base class of std::stringstream.

Here is another trick to turn a temporary into an l-value, so that any
operator>> can work on a temporary stream object:

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

This function template is supposed to be used like this:

lvalue(stringstream(a)) >> ...;

Alternatively, boost::lexical_cast<> converts between types using
streams and its usage is simpler:

int b = boost::lexical_cast<int>("1234");

Using streams directly as you do allows to extract more than one value
at once though.
 
J

Johannes Schaub (litb)

Maxim said:
Some stream operators are member functions, others are not. Member
functions can be called on temporary objects. boolalpha is handled by a
member function which returns std::istream&. That std::istream& can than
be accepted by both member and non-member operator>> functions.


Because extracting into an integer is handled by a member function of
std::istream base class of std::stringstream.

Here is another trick to turn a temporary into an l-value, so that any
operator>> can work on a temporary stream object:

template<class T>
inline T& lvalue(T const& t) {
return const_cast<T&>(t);
}
Although this will be ill-formed because it requires the stream to have a
copy constructor. You could also use this trickery which i believe is safe:

template<typename T>
struct Lv {
T t, &tr;
Lv():t(), tr(t) {}
};

template<typename T>
T &lvalue(T &t = Lv<T>().tr) { return t; }

"lvalue<stringstream>()" now gives an lvalue of type stringstream, but this
doesn't allow passing arguments to its constructor :(
 
J

Johannes Schaub (litb)

Johannes said:
Although this will be ill-formed because it requires the stream to have a
copy constructor. You could also use this trickery which i believe is
safe:

template<typename T>
struct Lv {
T t, &tr;
Lv():t(), tr(t) {}
};

template<typename T>
T &lvalue(T &t = Lv<T>().tr) { return t; }

"lvalue<stringstream>()" now gives an lvalue of type stringstream, but
this doesn't allow passing arguments to its constructor :(
If you want, though, you can change it to

template<typename T>
struct Lv {
T t, &tr;
Lv():t(), tr(t) {}
template<typename U1>
Lv(U1 const& u1):t(u1), tr(t) { }
};

And you can do Lv<stringstream>("hello").tr to get the lvalue, which isn't
too bad i think, it just doesn't look nice. Packaged into a macro

#define LVALUE(TY, EX) Lv<Ty> EX . tr

It can look much better like LVALUE(stringstream,("hello")) :)
 
M

Maxim Yegorushkin

Although this will be ill-formed because it requires the stream to have a
copy constructor.

Interesting.

My understanding is that a copy constructor is only required when copy
initialization is involved or when a conversion is made to initialize a
function argument. In this case there is no copy initialization or
conversion happening. Therefore, the code must be well formed.

Could you elaborate you point please?
 
A

Alf P. Steinbach

* Maxim Yegorushkin:
Interesting.

My understanding is that a copy constructor is only required when copy
initialization is involved or when a conversion is made to initialize a
function argument. In this case there is no copy initialization or
conversion happening. Therefore, the code must be well formed.

Could you elaborate you point please?

It's different in C++98 and C++0x (C++03 is just C++98 with corrections).

The argument passing is defined as copy initialization. And in C++98 the
implementation is allowed to make any number of copies of an rvalue actual
argument passed to 'T const&' formal argument, or for any copy initialization.
Which means that the type must provide a suitable copy constructor. For example,
that means that you can't do this thing with a std::auto_ptr. Or a stream.

In C++0x the implementation can't make such copies when it has an rvalue of
correct type, it must just pass (initialize the reference with) a direct
reference to the rvalue object. So this impacts on std::auto_ptr semantics,
which are different in C++0x. But with C++0x you don't have to and really
shouldn't use std::auto_ptr anyway, and even in C++98 passing std::auto_ptr by
reference to const is bad, and the "direct" passing provides a measure of
sanity. :)


Cheers & hth.,

- Alf
 
A

Alf P. Steinbach

* Alf P. Steinbach:
* Maxim Yegorushkin:

It's different in C++98 and C++0x (C++03 is just C++98 with corrections).

The argument passing is defined as copy initialization. And in C++98 the
implementation is allowed to make any number of copies of an rvalue
actual argument passed to 'T const&' formal argument, or for any copy
initialization. Which means that the type must provide a suitable copy
constructor. For example, that means that you can't do this thing with a
std::auto_ptr. Or a stream.

In C++0x the implementation can't make such copies when it has an rvalue
of correct type, it must just pass (initialize the reference with) a
direct reference to the rvalue object. So this impacts on std::auto_ptr
semantics, which are different in C++0x. But with C++0x you don't have
to and really shouldn't use std::auto_ptr anyway, and even in C++98
passing std::auto_ptr by reference to const is bad, and the "direct"
passing provides a measure of sanity. :)

Uhm, remove one "even", sorry.

Cheers,

- Alf
 
M

Maxim Yegorushkin

Alf said:
* Maxim Yegorushkin:

It's different in C++98 and C++0x (C++03 is just C++98 with corrections).

The argument passing is defined as copy initialization. And in C++98 the
implementation is allowed to make any number of copies of an rvalue
actual argument passed to 'T const&' formal argument, or for any copy
initialization. Which means that the type must provide a suitable copy
constructor. For example, that means that you can't do this thing with a
std::auto_ptr. Or a stream.

Even more interesting.

Given the following declaration:

void foo(int& ref);

Could you explain how ref argument can possibly be copy-initialized please?
 
V

Victor Bazarov

Maxim said:
Even more interesting.

Given the following declaration:

void foo(int& ref);

Could you explain how ref argument can possibly be copy-initialized please?

I am guessing the same way 'r2' is a "copy" of 'r1' here:

int a = 42;
int &r1 = a;
int &r2 = r1;

:)

V
 
M

Maxim Yegorushkin

Victor said:
I am guessing the same way 'r2' is a "copy" of 'r1' here:

int a = 42;
int &r1 = a;
int &r2 = r1;

:)

Very well, this is what I wanted to hear. ;)

In this case no copy constructor is required to copy-initialize a reference to
non-const. By induction, the same should hold true for references to const
(although they can be initialized with r-values, but only if necessary). Hence,
the above lvalue function template is well-formed.

Comeau online compiles lvalue(std::istringstream(...)) just fine.
 
J

Johannes Schaub (litb)

Maxim said:
Very well, this is what I wanted to hear. ;)

In this case no copy constructor is required to copy-initialize a
reference to non-const. By induction, the same should hold true for
references to const
(although they can be initialized with r-values, but only if necessary).
Hence, the above lvalue function template is well-formed.

Comeau online compiles lvalue(std::istringstream(...)) just fine.
Yes, but if you turn off the C++0x mode, it will error out.
 
J

James Kanze

Even more interesting.
Given the following declaration:
void foo(int& ref);
Could you explain how ref argument can possibly be
copy-initialized please?

There's more to it that Alf revealed. (It wouldn't be the C++
standard if it were that simple.) It's copy initialization, so
the rules for copy initialization apply. The rule that requires
a copy constructor when copy initialization is used only applies
when initializing a reference with an rvalue (and this is the
only time copies are allowed). If the initializer is an lvalue,
everything is fine---otherwise, things like:
int i;
int& ri = i;
would have somewhat unexpected semantics.
 
M

Maxim Yegorushkin

There's more to it that Alf revealed. (It wouldn't be the C++
standard if it were that simple.) It's copy initialization, so
the rules for copy initialization apply. The rule that requires
a copy constructor when copy initialization is used only applies
when initializing a reference with an rvalue (and this is the
only time copies are allowed). If the initializer is an lvalue,
everything is fine---otherwise, things like:
int i;
int& ri = i;
would have somewhat unexpected semantics.

I've been looking at 8.5 Initializers now. My understanding is that
because that form of initialization which is used for function arguments
is called copy initialization, it implies that a copy constructor is
required regardless of whether an argument is a reference that can be
bound directly. It also says that copy elision is a permissible
optimization, but does not require it.

My intuitive expectation is that implied by the spirit of C++: you don't
pay for what you don't use. Applied to the initialization of reference
function arguments I would expect it to require the copy constructor
only when it is actually used. Oh, well ;)

Alf and Johannes report that initialization of references does not
require a copy constructor in the C++0x standard. I am glad that they
elaborated this case :)
 
J

James Kanze

[...]
I've been looking at 8.5 Initializers now. My understanding is
that because that form of initialization which is used for
function arguments is called copy initialization, it implies
that a copy constructor is required regardless of whether an
argument is a reference that can be bound directly.

What part of 8.5 exactly? In §8.5/12,13, it says that the
initializer must be copied, but the initializer here would be
the T&, the reference. (That does have "interesting"
implications concerning the lifetime of temporaries, but I'm
pretty sure that that isn't intentional.) §8.5.3/5 is quite
clear: "[...]-- If the initializer expression [...]-- is an
lvalue[...] then the reference is bound directly to the
initializer expression."
It also says that copy elision is a permissible optimization,
but does not require it.

Yes, but since we're talking here about copying the reference, I
don't think that it's too relevant. References are copiable,
regardless of what they refer to. The possible problem
regarding copy is the lifetime of the temporary. Given
something like:
int const& ri = 3;
, the temporary containing the 3 has its lifetime extended to
that of the reference it initializes. If the reference it
initializes is a temporary, which is then copied to initialize
ri, this doesn't help us much.

As I said, I don't think this was intended, and I none of the
compilers I know implement it this way.
My intuitive expectation is that implied by the spirit of C++:
you don't pay for what you don't use. Applied to the
initialization of reference function arguments I would expect
it to require the copy constructor only when it is actually
used. Oh, well ;)

You don't want the legality of a program changed by whether the
compiler does some optional optimization or not.
Alf and Johannes report that initialization of references does
not require a copy constructor in the C++0x standard. I am
glad that they elaborated this case :)

I've still got to examine the new text. The reason for the rule
(I think) is for things like:

struct S { A a; B b; }; // A and B class types...
S f();

B const& rb = f().b;

What should be the lifetime of the S returned by f(). I'd argue
that the current text of the standard says that its lifetime
must end at the end of the full expression. But the only way to
end it, while extending the lifetime of the B temporary bound to
rb, is to copy it out of the S object. (A quick read of the
text in N2914---a recent, but perhaps not the latest,
draft---seems a bit ambiguous. None of the enumerated points
seems to cover this case.)
 
J

James Kanze

[...]
Very well, this is what I wanted to hear. ;)
In this case no copy constructor is required to
copy-initialize a reference to non-const. By induction, the
same should hold true for references to const (although they
can be initialized with r-values, but only if necessary).

Except when the standard explicitly says it is necessary. When
binding a reference to an rvalue, the present standard gives the
compiler the liberty of either binding the rvalue object
directly, or binding a copy of the rvalue object (which is
necessary in certain cases to respect object lifetime); since it
doesn't want the legality of a program to depend on
implementation choices, it requires an accessible copy
constructor in all cases.

The next version of the standard is more explicit, requiring the
copy explicitly in some cases (i.e. when it would be necessary
for lifetime of object reasons), and forbidding it in others;
when it is forbidden, the compiler is not allowed to make the
copy, and no copy constructor is required.
Hence, the above lvalue function template is well-formed.
Comeau online compiles lvalue(std::istringstream(...)) just fine.

It shouldn't, according to C++03. The next version of the
standard will allow it, however. (I think, too, that a lot of
current compilers also allow it---g++ being the major
exception.)
 
P

Pavel

James said:
On Oct 26, 4:07 pm, Maxim Yegorushkin<[email protected]>
wrote:
[...]
The argument passing is defined as copy initialization. And
in C++98 the implementation is allowed to make any number of
copies of an rvalue actual argument passed to 'T const&'
formal argument, or for any copy initialization. Which means
that the type must provide a suitable copy constructor. For
example, that means that you can't do this thing with a
std::auto_ptr. Or a stream.
Even more interesting.
Given the following declaration:
void foo(int& ref);
Could you explain how ref argument can possibly be
copy-initialized please?
There's more to it that Alf revealed. (It wouldn't be the
C++ standard if it were that simple.) It's copy
initialization, so the rules for copy initialization apply.
The rule that requires a copy constructor when copy
initialization is used only applies when initializing a
reference with an rvalue (and this is the only time copies
are allowed). If the initializer is an lvalue, everything
is fine---otherwise, things like:
int i;
int& ri = i;
would have somewhat unexpected semantics.
I've been looking at 8.5 Initializers now. My understanding is
that because that form of initialization which is used for
function arguments is called copy initialization, it implies
that a copy constructor is required regardless of whether an
argument is a reference that can be bound directly.

What part of 8.5 exactly? In §8.5/12,13, it says that the
initializer must be copied, but the initializer here would be
the T&, the reference. (That does have "interesting"
implications concerning the lifetime of temporaries, but I'm
pretty sure that that isn't intentional.) §8.5.3/5 is quite
clear: "[...]-- If the initializer expression [...]-- is an
lvalue[...] then the reference is bound directly to the
initializer expression."
It also says that copy elision is a permissible optimization,
but does not require it.

Yes, but since we're talking here about copying the reference, I
don't think that it's too relevant. References are copiable,
regardless of what they refer to. The possible problem
regarding copy is the lifetime of the temporary. Given
something like:
int const& ri = 3;
, the temporary containing the 3 has its lifetime extended to
that of the reference it initializes. If the reference it
initializes is a temporary, which is then copied to initialize
ri, this doesn't help us much.

As I said, I don't think this was intended, and I none of the
compilers I know implement it this way.
My intuitive expectation is that implied by the spirit of C++:
you don't pay for what you don't use. Applied to the
initialization of reference function arguments I would expect
it to require the copy constructor only when it is actually
used. Oh, well ;)

You don't want the legality of a program changed by whether the
compiler does some optional optimization or not.
Alf and Johannes report that initialization of references does
not require a copy constructor in the C++0x standard. I am
glad that they elaborated this case :)

I've still got to examine the new text. The reason for the rule
(I think) is for things like:

struct S { A a; B b; }; // A and B class types...
S f();

B const& rb = f().b;

What should be the lifetime of the S returned by f(). I'd argue
that the current text of the standard says that its lifetime
must end at the end of the full expression. But the only way to
end it, while extending the lifetime of the B temporary bound to
rb, is to copy it out of the S object.
Why does the lifetime of B temporary has to be extended? Do you imply
this because the lifetime of rb extends beyond the one of S temporary?
 
J

James Kanze

James Kanze wrote:

[...]
Why does the lifetime of B temporary has to be extended?

Because the standard says so. When a reference is initialized
with a temporary, the lifetime of that temporary is extended to
match that of the reference. (See §12.2.)
Do you imply this because the lifetime of rb extends beyond
the one of S temporary?

Yes. The standard clearly requires that the lifetime of the
temporary bound to the reference be extended to that of the
reference. It also clearly requires that the lifetime of the
temporary S terminate at the end of the full expression. The
current standard allows a copy here, and the compilers I've
checked in the past (and the one I have access to at present:
VC++) do make a copy. The current draft forbids the copy here,
while not changing any of the other requirements; I'm not sure
how they expect this to be implemented.
 

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

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top