472,789 Members | 1,175 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 472,789 software developers and data experts.

istringstream("XXX") >> x;

I would like to do this

MyClass x;
istringstream("XXX") >> x; // Works in VC++ but not GCC

instead of

MyClass x;
istringstream iss("XXX");
iss >> x; // Works in both GCC and VC++

In other words I would like to be able to use istringstream without
having to declare (and name) an object for the stream. This works fine
in VC++ but not in GCC. It appears that it fails to compile in GCC
because the copy constructor for ios_base is private.

The strange thing is that GCC will compile this like I want if the type
I'm extracting into is a native type instead of a user defined type.

double x;
istringstream("10.4") >> x; // Works in both GCC and VC++

compiles and works in GCC. Is what I want to do legal use of
istringstream? Is there anything I can do to classes I define to make
this work in GCC? It's really annoying to have to declare a variable
with a name when I just want to extract some value from a string.

Thanks,
Ryan

Jan 4 '06 #1
11 2827
ic*****@gmail.com wrote:
I would like to do this

MyClass x;
istringstream("XXX") >> x; // Works in VC++ but not GCC

instead of

MyClass x;
istringstream iss("XXX");
iss >> x; // Works in both GCC and VC++

In other words I would like to be able to use istringstream without
having to declare (and name) an object for the stream. This works fine
in VC++ but not in GCC. It appears that it fails to compile in GCC
because the copy constructor for ios_base is private.
My guess is that you somehow defined your operator >> as

void ::operator >> (istream, MyClass&);

whereas you ought to do it like this:

istream& ::operator >> (istream&, MyClass&);

.. The latter form requires no copy-construction.
The strange thing is that GCC will compile this like I want if the type
I'm extracting into is a native type instead of a user defined type.

double x;
istringstream("10.4") >> x; // Works in both GCC and VC++

compiles and works in GCC.
That's because operator>>(double&) is a _member_.
Is what I want to do legal use of
istringstream?
Depends.
Is there anything I can do to classes I define to make
this work in GCC? It's really annoying to have to declare a variable
with a name when I just want to extract some value from a string.


Yes, it is. Fix it.

V
Jan 4 '06 #2
> My guess is that you somehow defined your operator >> as

void ::operator >> (istream, MyClass&);

whereas you ought to do it like this:

istream& ::operator >> (istream&, MyClass&);

No, I didn't do that. Does the following program work for you in GCC?
It doesn't compile for me.

#include <iostream>
#include <sstream>

using namespace std;

struct MyClass {};

istream& operator>>(istream& i, MyClass& x) {
cout << "Hello" << endl;
return i;
}

int main() {
MyClass x;
istringstream("XXX") >> x;

double y;
istringstream("10.4") >> y;

return 0;
}

Jan 4 '06 #3
ic*****@gmail.com wrote:
My guess is that you somehow defined your operator >> as

void ::operator >> (istream, MyClass&);

whereas you ought to do it like this:

istream& ::operator >> (istream&, MyClass&);


No, I didn't do that. Does the following program work for you in GCC?
It doesn't compile for me.

#include <iostream>
#include <sstream>

using namespace std;

struct MyClass {};

istream& operator>>(istream& i, MyClass& x) {
cout << "Hello" << endl;
return i;
}

int main() {
MyClass x;
istringstream("XXX") >> x;

double y;
istringstream("10.4") >> y;

return 0;
}


My bad. This won't work either. The problem is that a temporary cannot
be bound to a reference to non-const, which of course would be required to
initialise the first argument of your overloaded operator>>. I guess when
I suggested it, I wasn't fully awake.

A work-around for you would be to have a custom constructor from a string,
where internally you'll create an istringstream and do as you do in your
overloaded operator:

struct MyClass {
explicit MyClass(const std::string& str) {
std::istringstream is(str);
is >> ... // members are extracted
}
};

and when you need to "read" your MyClass from a string, do

MyClass x("XXX");

V
Jan 4 '06 #4

"Victor Bazarov" <v.********@comAcast.net> wrote in message
news:8u*******************@newsread1.mlpsca01.us.t o.verio.net...
ic*****@gmail.com wrote: ....
My bad. This won't work either. The problem is that a temporary cannot
be bound to a reference to non-const, which of course would be required to
initialise the first argument of your overloaded operator>>. I guess when
I suggested it, I wasn't fully awake.

A work-around for you would be to have a custom constructor from a string,
where internally you'll create an istringstream and do as you do in your
overloaded operator:

struct MyClass {
explicit MyClass(const std::string& str) {
std::istringstream is(str);
is >> ... // members are extracted
}
};

and when you need to "read" your MyClass from a string, do

MyClass x("XXX");


See http://www.boost.org/libs/conversion/lexical_cast.htm

{
try
{
MyClass x( boost::lexical_cast<MyClass>( "XXX" ) );

...

}
catch(bad_lexical_cast &)
{
...
}

...

}

Jeff Flinn

Jan 4 '06 #5
That's exactly what I was looking for. I guess istringstream is just
not able to do what I wanted. Thanks a lot! The following program
works.
#include <iostream>
#include <boost/lexical_cast.hpp>

using namespace std;
using namespace boost;

struct MyClass {};

istream& operator>>(istream& i, MyClass& x) {
cout << "Hello" << endl;
while (!i.eof()) i.get();
i.clear();
return i;
}

int main() {
MyClass x = lexical_cast<MyClass>("XXX");
return 0;
}

Jan 4 '06 #6
ic*****@gmail.com wrote:
That's exactly what I was looking for. I guess istringstream is just
not able to do what I wanted. Thanks a lot! The following program
works.
#include <iostream>
#include <boost/lexical_cast.hpp>

using namespace std;
using namespace boost;

struct MyClass {};

istream& operator>>(istream& i, MyClass& x) {
cout << "Hello" << endl;
while (!i.eof()) i.get();
i.clear();
return i;
}

int main() {
MyClass x = lexical_cast<MyClass>("XXX");
return 0;
}


Implement your own "lexical_cast" as

MyClass my_lexical_cast(const std::string &s)
{
std::istringstream is(s);
MyClass temp;
is >> temp;
return temp;
}

and you don't need Boost. The fewer third-party libraries you use, the
easier it is to maintain your code.

But notice that the use of a _named_temporary_object_ is what you end up
doing anyway (you tried to avoid that). You just wrapped it in a function
(or use Boost's wrapper).

V
Jan 4 '06 #7
Victor Bazarov wrote:
The problem is that a temporary cannot
be bound to a reference to non-const, [...]


Does anyone know the reason for that?

Martin.
Jan 5 '06 #8
Martin Vejnar wrote:
Victor Bazarov wrote:
The problem is that a temporary cannot
be bound to a reference to non-const, [...]

Does anyone know the reason for that?


I know I should, but I can't recall anything in particular. Try searching
the news archives, I am fairly certain that question has already come up
more than once...

<ok, I looked it up in D&E> The reason is that this mechanism exists to
allow a non-lvalue to be passed to a function that accepts references.
Passing a non-lvalue may require a conversion. Allowing a reference to
non-const to be bound to a temporary created as the result of such
conversion causes trouble. BS gives this example:

void incr(int& rr) { rr++; }

void g()
{
double ss = 1;
incr(ss); // note: double passed, int expected
}

Inside the 'g' function when 'incr' is called, if it were allowed,
a temporary of type 'int' would be created and incremented inside the
'incr' function. That increment would have no effect on 'ss', which is
likely not the desired behaviour. The resolution is to prohibit binding
references to non-const to temporaries.

V
Jan 5 '06 #9
Victor Bazarov wrote:
Martin Vejnar wrote:
Victor Bazarov wrote:
The problem is that a temporary cannot
be bound to a reference to non-const, [...]


Does anyone know the reason for that?


<ok, I looked it up in D&E> [...]


Thank you :o)
Martin.
Jan 5 '06 #10

Victor Bazarov wrote:
ic*****@gmail.com wrote:

Implement your own "lexical_cast" as

MyClass my_lexical_cast(const std::string &s)
{
std::istringstream is(s);
MyClass temp;
is >> temp;
return temp;
}

and you don't need Boost. The fewer third-party libraries you use, the
easier it is to maintain your code.

But notice that the use of a _named_temporary_object_ is what you end up
doing anyway (you tried to avoid that). You just wrapped it in a function
(or use Boost's wrapper).

V


I agree with you but for a slightly different reason. The problem with
boost::lexical_cast is in the exception it throws. It has meaningless
text, does not describe the invalid string that was input so you cannot
pass this back to your user who has to handle the exception - remember
that a bad lexical cast will usually come from some error in the user's
input / config file / XML or whatever. So effectively it means you
always have to run your bosot::lexical_cast in a try..catch and
re-throw a new exception every time.

In addition, my own ones derive from a base-class of converters, which
allows you to select what type of converter you want. Some of them
don't even throw an exception, they treat the error in a different way,
eg as an N/A. (With float or double you can store that as a quiet_NaN,
with a class as a zombie, with a pointer as NULL, with an int - oh well
pick a number.... 0x80000000 is often a good choice ).

By the way, you can make it a template. Two issues to bear in mind:

- After streaming to your object, check the stream is now empty. 123abc
is not a valid int but will not give a "fail" state if you try
streaming it to one.

- Be sure to specialise for string, not just because converting to
istringstream and back is inefficient but because it will also chop at
the first whitespace.

Jan 5 '06 #11
ic*****@gmail.com wrote:
I guess istringstream is just
not able to do what I wanted.


It actually is! Although this is somewhat against the intention of
the rule prohibiting binding a temporary to a non-const reference,
you can simply change the line

std::istringstream("XXX") >> x;

to become

std::istringstream("XXX") >> std::noskipws >> x;

and it works (instead of 'noskipws' you can use any other manipulator,
too, which does not change the state of the stream). The reason why
this works is simple: the manipulators use member functions of the
stream class which don't need to be bound to a non-const reference to
be called. However, these member functions return a non-const reference
which can then be used by the user defined extraction function.
--
<mailto:di***********@yahoo.com> <http://www.dietmar-kuehl.de/>
<http://www.eai-systems.com> - Efficient Artificial Intelligence
Jan 6 '06 #12

This thread has been closed and replies have been disabled. Please start a new discussion.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.