You can't make an istringstream
read from any external source: it always makes a copy, even of a single string. You can, however, make a stream that reads from any data source by making your own streambuf
class and making an istream
from a pointer to an instance of it. A minimal version needs only one method overridden:
#include<streambuf>
#include<string>
#include<vector>
struct stringsbuf : std::streambuf {
stringsbuf(const std::string *b,const std::string *e) : ss(b),se(e) {}
stringsbuf(const std::vector<std::string> *v) : // pointer vs. temporaries
ss(&v->front()),se(ss+v->size()) {}
int_type underflow() override {
while(ss!=se) {
auto &s=*ss++;
if(s.empty()) continue;
char *p=const_cast<char*>(s.data());
setg(p,p,p+s.size());
return *p;
}
return traits_type::eof();
}
private:
const std::string *ss,*se; // next string to load, and past-the-end string
};
This could of course be made more efficient and featureful by adding one or more of xsgetn
, seekoff
, seekpos
, and showmanyc
. It could also be made generic (not only on character type, but also by accepting any string
-valued iterators).
The elegance here lies in the fact that no concatenated string is ever constructed (except perhaps by the client that reads from an istream
based on a stringsbuf
).