For an easy solution, use boost
's join with ranges of istream iterators for the files. I am unaware of a similar function in the current C++ library, but one probably exists in the TS Rangesv3.
You can also write it yourself: writing join yourself is perfectly possible.
I'd write it as a "flattening" input-only iterator -- an iterator over a range of ranges that iterates over the contents of each range in turn. The iterator would keep track of the future range of ranges, and an iterator for the current element.
Here is a very simple zip iterator to give you the idea of the magnitude of code you'd have to write (a zip iterator is a different concept, and this is a simple one only suitable for a for(:)
loop).
This is a sketch of how you might do it using C++14:
template<class It>
struct range_t {
It b{};
It e{};
It begin() const { return b; }
It end() const { return e; }
bool empty() const { return begin()==end(); }
};
template<class It>
struct range_of_range_t {
std::deque<range_t<It>> ranges;
It cur;
friend bool operator==(range_of_range_t const& lhs, range_of_range_t const& rhs) {
return lhs.cur==rhs.cur;
}
friend bool operator!=(range_of_range_t const& lhs, range_of_range_t const& rhs) {
return !(lhs==rhs);
}
void operator++(){
++cur;
if (ranges.front().end() == cur) {
next_range();
}
}
void next_range() {
while(ranges.size() > 1) {
ranges.pop_front();
if (ranges.front().empty()) continue;
cur = ranges.front().begin();
break;
}
}
decltype(auto) operator*() const {
return *cur;
}
range_of_range_t( std::deque<range_t<It>> in ):
ranges(std::move(in)),
cur{}
{
// easy way to find the starting cur:
ranges.push_front({});
next_range();
}
};
the iterator needs work, in that it should support all of the iterator axioms. And getting the end iterator right is a bit of work.
This isn't a strema, but rather an iterator.