2

I have a null-terminated character string stored in s of type char*. I want to create an istringstream object from s. Since the constructor of istringstream expects a parameter of type string, I need to convert s from char* to string. I did this by creating an anonymous string object from s using its constructor in the following way:

istringstream strin(string(s));

This seems OK when compiled using gcc (4.7.3). However, after I added the following codes to use strin

int r;
strin >> r;

I got the compile error:

error: invalid operands of types 'std::istringstream(std::string*) {aka std::basic_istringstream<char>(std::basic_string<char>*)}' and 'int' to binary 'operator>>'

This seems weird to me since I don't understand what the type std::istringstream(std::string*) is. Shouldn't strin be of type std::istringstream?

I can keep the compiler happy by using one of the following modified versions of the code.

Solution 1: pass a named string object

string str(s);
istringstream strin(str);

Solution 2: directly pass s, seems like it will be implicitly converted to string

istringstream strin(s);

Solution 3: explicitly convert s to string

istringstream strin((string)(s));

Solution 4: add a pair of magical parentheses

istringstream strin((string(s)));

Solution 5: tell the compiler s is indeed a char* type

istringstream strin(string((char*)s));

All this works except the original one. Could anybody explain what is really going on here? Thanks.

starforever
  • 107
  • 1
  • 6
  • search for: *Most vexing parse*.. read all about it.. ;), btw, my preference is for solution 2.... – Nim Aug 12 '13 at 08:29

2 Answers2

4

The most vexing parse strikes again:

std::istringstream strin( string( s ) );

declares a function (strin) which takes a string as argument, and returns an std::istringstream. (A good compiler could warn here, because there's no way you can possible implement such a function.) The simplest way of correcting this is to add some extra parentheses:

std::stringstream strin( (string( s )) );

(Actually, the simplest solution here is to just write:

std::stringstream strin( s );

and let the implicit conversion do the job.)

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • Why is it impossible to implement this function? I thought streams are movable now. – jrok Aug 12 '13 at 08:41
  • or if the conversion has to be explicit, use C++11 uniform initialization: `std::stringstream strin{ string{ s } };` – Arne Mertz Aug 12 '13 at 08:41
  • *"A good compiler could warn here, because there's no way you can possible implement such a function"*. Why such function cannot be implemented? Is it because the stream classes are non-copyable? Or? – Nawaz Aug 12 '13 at 08:48
  • @jrok Ah, today yes. But not unless you're using C++11 (and realistically, most people probably can't). – James Kanze Aug 12 '13 at 08:51
  • @Nawaz Yes. But of course, C++ makes them movable, so the restriction no longer applies. (Which in this case, it a good thing.) – James Kanze Aug 12 '13 at 08:52
1

This is the "most vexing parse" issue.

istringstream strin(string(s));

This is not a strin variable declaration but a declaration of a function taking string, returning istringstream that is named strin.

You can fix this case like this. Notice the + there. While s is identifier, +s is an expression.

istringstream strin(string(+s));
wilx
  • 17,697
  • 6
  • 59
  • 114