Reputation: 10855
I have the following code in C++:
string str="a b c";
stringstream sstr(str);
vector<string> my_vec((istream_iterator<string>(sstr)),
istream_iterator<string>());
Is there any way to save the use of sstr
, something like the following?
vector<string> my_vec((istream_iterator<string>(str)),
istream_iterator<string>());
Upvotes: 0
Views: 399
Reputation: 299790
Boost has a library dedicated to algorithm on string: check out the Split section :)
std::vector<std::string> vec;
boost::split(vec, "a b c", boost::is_any_of(" "));
// vec == { "a", "b", "c" }
Probably the clearest way to do it :)
Upvotes: 0
Reputation: 42805
You're using the two-iterator constructor for vector
with istream_iterator
to split the string by whitespace into a sequence of strings to be stored.
istream_iterator
needs an istream
, for which there is no direct cast from string
. The compiler is not going to infer a stringstream
because the constructor for istream_iterator
takes a templated type and not explicitly a stringstream
. It's just too much of a leap for a compiler to assume that much.
Besides, even if the compiler made such a leap of faith, it would generate the same code as what you already have, so you're no better off in the end.
A better approach might be:
std::vector<std::string> split_words(const std::string& str)
{ size_t offset = str.find_first_not_of(" \t\r\n");
std::vector<std::string> result;
while(offset != std::string::npos)
{ size_t end = str.find_first_of(" \t\r\n", offset);
if(end != offset)
result.push_back(std::string(str, offset, end));
offset = str.find_first_not_of(" \t\r\n", end);
}
return result;
}
which takes less code and objects to get the same job done. On my Mac, this is 3203 bytes code and 273 data, while the original three lines of code is 5136 bytes code and 353 data. (I added return my_vec.size();
at the end of main()
.)
Upvotes: 0
Reputation: 503815
istream_iterator
's argument needs to be able to bind to a non-const reference, and a temporary cannot. However, (as Alf points out), ostream
happens to have a function, flush()
, that returns a non-const reference to itself. So a possibility is:
string str="a b c";
vector<string> my_vec(istream_iterator<string>(
static_cast<stringstream&>(stringstream(str).flush())
), istream_iterator<string>());
Though that's an eye-sore. If you're concerned about having too many lines, then use a function:
vector<string> string_to_vector(const string& str)
{
stringstream sstr(str);
return vector<string>(istream_iterator<string>(sstr),
istream_iterator<string>());
}
Giving:
string str="a b c";
vector<string> my_vec = string_to_vector(str);
This is even cleaner than what you'd get even if you could shorten your code, because now what is being done is not expressed in code but rather the name of a function; the latter is much easier to grasp.
*Of course, we can add boiler-plate code to do silly things:
class temporary_stringstream
{
public:
temporary_stringstream(const string& str) :
mStream(str)
{}
operator stringstream&()
{
// only persists as long as temporary_stringstream!
return mStream;
}
private:
stringstream mStream;
};
Giving:
string str="a b c";
vector<string> my_vec((istream_iterator<string>(temporary_stringstream(str))),
istream_iterator<string>());
But this is just as ugly as the first solution.
Upvotes: 4