Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Why extracting string from stringstream(a) fails?

14 views
Skip to first unread message

Mc Lauren Series

unread,
Oct 24, 2009, 5:00:51 PM10/24/09
to
#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::char_traits<char>, std::allocator<char> >&)((const
std::basic_string<char, std::char_traits<char>, std::allocator<char>
>*)(& a))), std::operator|(_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?

Victor Bazarov

unread,
Oct 24, 2009, 6:28:34 PM10/24/09
to

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
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask

Mc Lauren Series

unread,
Oct 25, 2009, 2:17:08 AM10/25/09
to

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?

Maxim Yegorushkin

unread,
Oct 25, 2009, 6:36:29 AM10/25/09
to

>


> 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.

--
Max

Johannes Schaub (litb)

unread,
Oct 25, 2009, 2:13:07 PM10/25/09
to
Maxim Yegorushkin wrote:

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 :(

Johannes Schaub (litb)

unread,
Oct 25, 2009, 2:17:39 PM10/25/09
to
Johannes Schaub (litb) wrote:

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")) :)


Maxim Yegorushkin

unread,
Oct 25, 2009, 6:37:51 PM10/25/09
to

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?

--
Max

Alf P. Steinbach

unread,
Oct 25, 2009, 6:51:34 PM10/25/09
to
* 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. :-)


Cheers & hth.,

- Alf

Alf P. Steinbach

unread,
Oct 25, 2009, 6:52:49 PM10/25/09
to
* Alf P. Steinbach:

Uhm, remove one "even", sorry.

Cheers,

- Alf

Maxim Yegorushkin

unread,
Oct 26, 2009, 11:07:11 AM10/26/09
to

Even more interesting.

Given the following declaration:

void foo(int& ref);

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

--
Max

Victor Bazarov

unread,
Oct 26, 2009, 11:14:53 AM10/26/09
to

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

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

:-)

Maxim Yegorushkin

unread,
Oct 26, 2009, 11:36:09 AM10/26/09
to

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.

--
Max

Johannes Schaub (litb)

unread,
Oct 26, 2009, 12:05:34 PM10/26/09
to
Maxim Yegorushkin wrote:

Yes, but if you turn off the C++0x mode, it will error out.

James Kanze

unread,
Oct 26, 2009, 1:47:52 PM10/26/09
to
On Oct 26, 4:07 pm, Maxim Yegorushkin <maxim.yegorush...@gmail.com>
wrote:

> >> Interesting.

> Even more interesting.

> Given the following declaration:

> void foo(int& ref);

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.

--
James Kanze

Maxim Yegorushkin

unread,
Oct 26, 2009, 7:02:11 PM10/26/09
to

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 :)

--
Max

James Kanze

unread,
Oct 28, 2009, 10:29:46 AM10/28/09
to
On Oct 26, 11:02 pm, Maxim Yegorushkin <maxim.yegorush...@gmail.com>

wrote:
> On 26/10/09 17:47, James Kanze wrote:
> > On Oct 26, 4:07 pm, Maxim Yegorushkin<maxim.yegorush...@gmail.com>
> > wrote:

[...]

> >> Even more interesting.

> >> Given the following declaration:

> >> void foo(int& ref);

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.)

--
James Kanze

James Kanze

unread,
Oct 29, 2009, 5:12:24 AM10/29/09
to
On Oct 26, 3:36 pm, Maxim Yegorushkin <maxim.yegorush...@gmail.com>
wrote:

> Victor Bazarov wrote:
> > Maxim Yegorushkin wrote:

[...]
> >> 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;

> > :-)

> 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.)

--
James Kanze

Pavel

unread,
Oct 31, 2009, 2:45:20 PM10/31/09
to
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?

James Kanze

unread,
Nov 2, 2009, 4:49:32 AM11/2/09
to
On Oct 31, 6:45 pm, Pavel
<pauldontspamt...@removeyourself.dontspam.yahoo> wrote:
> James Kanze wrote:

[...]


> > 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?

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.

--
James Kanze

0 new messages