tags:

views:

254

answers:

5

When I try to declare iss using the first form, g++ gives me "error: no match for 'operator>>' in 'iss >> s'". But don't the two different declarations do the same thing?

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


int main() {
    const char *buf = "hello world";
    std::string ss(buf);
    //std::istringstream iss(std::string(buf)); // this doesn't work
    std::istringstream iss(ss); // but this does
    std::string s;
    iss >> s;
}
A: 

Don't you need to use namespace std;?

Jaba
No, he's prefixed everything that's in the std namespace.
Paul Tomblin
Ok I'm sorry!! you don't need to vote me off the island if I was wrong I made a mistake, everyone does. Give a guy a break!!
Jaba
It's not meant as a personal vendetta – it's just an indicator that your answer is wrong, which is part of what voting is for.
Perspx
+8  A: 

It's because istringstream takes a const reference to a string. So you can't just write this:

std::istringstream iss(std::string(buf));

Well, actually you can, but it means you are declaring a function iss, which takes a std::string and returns std::istringstream. Equivalently, you could write:

std::istringstream iss(std::string buf);

It's pretty sick C++ stuff.

A: 

I guess there is some confusion about the type returned by std::string(char*) because this:

  std::istringstream iss((std::string)std::string(buf));

works.

Martin Redmond
This is because without the cast it declares a function called `iss` which accepts a `std::string` and returns a `std::istringstream` (the brackets around the argument name are optional). Since a cast cannot appear in declaring function arguments, this must be clearly a *call* to something that accepts a `std::string` (`istringstream`'s constructor).
UncleBens
A: 

The first argument to construct an istream from a string needs to be: const string & str which this does not create:

    std::string(buf)

While the following code illustrates the point, it leaks memory, so don't actually use it.

    std::istringstream iss(*new std::string(buf));
NVRAM
+10  A: 

This is known as the "most vexing parse" of C++: what looks like an instance declaration to you actually looks like a function declaration to the compiler.

std::string name(); //function declaration
std::string name;  //object declaration with default constructor

std::stringstream ss(std::string(buf));  //function declaration
std::stringstream ss(std::string buf);  //another function declaration
std::stringstream ss(std::string);  //also a function declaration
std::stringstream ss(std::string());  //ditto, argument names are optional

std::stringstream ss((std::string(buf))); //object declaration

Note the extra brackets in the last example. These brackets wouldn't be legal in a function declaration.

The first example with the default constructor is well-known. What adds unclarity in the second case is that brackets around parameter names in C++ are legal but optional. For example, you can define a function like this:

void foo(int (bar))
{}

Basically you'll run into this every time when all arguments to a constructor are temporaries from constructor invocations that take 0 or 1 arguments, and the quick solution is to put extra brackets around one of the arguments.

UncleBens