Passing temporary istringstream object to istream_

2019-02-25 11:36发布

I have a question about the following code that tokenizes a string (separates the tokens by space).

#include <iostream>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>

using namespace std;

int main()
{
    string s="And I feel fine ...";
    istringstream ss(s);
    vector<string> tokens{istream_iterator<string>(ss),{}};
    for(auto& elem: tokens)
        cout << elem << endl;
}

This works perfectly fine. On the other hand, if I try to pass a temporary istringstream object to istream_iterator (3-rd line inside main), such as

vector<string> tokens{istream_iterator<string>(istringstream(s)),{}};

I am getting a compile-time error error: no matching conversion for functional-style cast from 'istringstream' (aka 'basic_istringstream<char>') to 'istream_iterator<string>'

I believe it is because I cannot bound a temporary rvalue to a non-const lvalue reference, and the constructor of istream_iterator takes a reference as a parameter. Is there any way of constructing an istream_iterator<string> from a temporary? I cannot use std::ref on a temp object either...

Thanks!

1条回答
萌系小妹纸
2楼-- · 2019-02-25 11:43

Use the std::skipw trick:

std::vector<std::string> tokens{
    std::istream_iterator<std::string>(std::istringstream(s) >> std::skipws), {}
};

This works because the extractor returns an lvalue-reference to the stream, and setting std::skipw won't have any effect because it is enabled by default on all streams. To use this in the general case, you would want to have a function that takes a universal reference, then returns a reference to that object:

template<typename T>
T& lvalue(T&& x)
{
    return x;
}

// ...
std::istream_iterator<std::string>(lvalue(std::istringstream(s)));

Make sure the reference isn't being used past the full expression, or else you'll have a dangling reference as the temporary will have already been destructed.

查看更多
登录 后发表回答