4

I want to use an existing view for concatenation. In code:

auto rng = view::empty<vector<int>>();

for(int i{0}; i < 5; ++i)
{
    vector<int> const & v{foo()}; // returns a reference
    rng |= view::concat(v); // doesn't compile - error: no viable overloaded '|='
};

In other words - how can I create a view to multiple vectors whose number is not known until runtime?

nikitablack
  • 4,359
  • 2
  • 35
  • 68
  • What type is `newRange` and can we see the `foo()` function? Also what is `v` for? – Galik Apr 02 '17 at 14:55
  • @Galik I updated the code. The `foo()` function returns a const reference, but it's not relevant to my question. – nikitablack Apr 02 '17 at 16:24
  • I think this is quite difficult to do with the ranges. Consider n ranges with different elements. Now a begin() and end() of the overall range points to begin() of the first, and end() of the last, and in between it has to keep track of whether we are at the end of kth range, and move to (k+1)th. ``view::concat`` at compile time achieves this with quite a heavy bit of machinery. – skgbanga Apr 02 '17 at 21:30

1 Answers1

5

You can't compose views this way. Concatenating a view yields an object with a different type. You can't assign it back to the original view because its type is different.

You can get the effect you're after with a combination of view::cycle (takes one range and repeats it infinitely), and view::take (takes the first N elements of a range).

vector<int> const & v{foo()}; // returns a reference
auto rng = v | view::cycle | view::take(5 * v.size());

EDIT

If foo() can return a reference to a different vector each time, then you can use view::generate and view::join, in addition to view::take:

auto rng = view::generate(foo) | view::take(5) | view::join;
Eric Niebler
  • 5,927
  • 2
  • 29
  • 43
  • This won't do what you want if `foo()` returns different vectors from multiple calls. You would need a flattening (`view::join`?) operation to compose that – Caleth Apr 03 '17 at 18:47
  • 1
    @Eric Can this be done with a type erased iterator range? (This will require changes in range-v3 library code of course). But basically we have a Range which has a begin/end and internally keeps a list/zip of begin and end values. While iterating, it keeps track of kth range and move to (k+1)th at the end. Btw, this is super similar to how a deque is implemented. And this can be made to model RandomAccessIterator. Whether all this is useful is a different matter :) – skgbanga Apr 03 '17 at 21:29
  • 1
    @skgbanga, yes this could be done with type-erasure, but I don't recommend it. – Eric Niebler Apr 03 '17 at 21:45
  • Thank you, for my example it works. But what if I have a list of vectors (`std::vector>`)? How can I create a single view to all (or maybe only to some) vectors? Or even better - if I have a list of futures and each future returns a reference to a vector. – nikitablack Apr 04 '17 at 07:11