I must admit I quite like Potatoswatter solution... quite.
As he demonstrated, this is not an issue of algorithm, but of iteration. However his solution does not quite fit the bill because testing for the end
of the iteration is very difficult: it requires much care in the preparation of the containers and the creation of the iterators to avoid undefined behavior.
I think the problem could be much better expressed using a concept that is quite similar to iterators: views.
A view is an Adapter interface over one or several containers. It doesn't actually contain anything itself (that's the important part). It does however exposes an interface similar to that of a container so that you can code with the usual idioms.
The beautiful things about views, is that you can often compose them.
For example, one very simple view:
/// Only allow to see a range of the container:
/// std::vector<int> v(40, 3); // { 3, 3, 3, ... }
/// auto rv = make_range_view(v, 4, 5);
/// rv exposes the elements in the range [4,9)
/// in debug mode, asserts that the range is sufficiently large
template <typename Container>
class range_view
{
};
For your question, you would rather create an interleave_view
:
/// Allow to interleave elements of 2 containers each at its own pace
/// std::vector<int> v(40, 3);
/// std::set<int> s = /**/;
///
/// auto iv = make_interleave_view(v, 3, s, 1);
/// Takes 3 elements from v, then 1 from s, then 3 from v, etc...
template <typename C1, typename C2>
class interleave_view
{
};
Here the issue of the end iterator is somehow alleviated because we know both containers and thus we are able to create the iterators ourselves, ensuring we pass the proper parameters.
Of course it can become a bit more tedious if the containers do not offer an efficient "size" member (list
doesn't, it's O(n)).
The general principle however is that a view gives you more control (and allows more checks), and is safer to use because you control precisely the creation of the iterators.
Note that in C++0x the interleave_view
would typically accomodate an unbounded number of sequences.