1

To illustrate what I mean: I have three objects:

Foo first, even, odd;

And I want to construct a view consisting of references to these objects like this: first&, odd&, even&, odd& ... up to N. To be able to iterate over them:

for (const auto & obj: my_view) {
    // obj is equal to first&, odd&, even&, odd&... and so on
}

or pass the view to a function:

template <typename V>
void parse_elements(const V & v) {
    // iterate over elements here
}

Is this possible with the most recent std::ranges or v3 ranges libraries without writing my own container class?

cos
  • 940
  • 1
  • 10
  • 25
  • What is `N`? Does `first` only appear one time and then (odd, even) repeats? – Barry Mar 24 '21 at 12:56
  • N is a dynamic variable. That's correct `first` is the first element and then `even`, `odd` repeats to make a list of N elements. But this is just an illustration. I hope that the solution could be used for different patterns. – cos Mar 24 '21 at 12:58

4 Answers4

3

Firstly, I recommend starting off with arrays of Foo objects instead of distinct variables. This isn't necessary as you can use spans instead, but this is a bit more straightforward:

Foo first[1] {};
Foo even_odd[2] {};

Ranges-v3 has cycle and concat views that are useful in this case. They aren't in the standard library:

namespace views = ranges::views;
auto even_odd_cycle = even_odd | views::cycle;
auto first_even_odd = views::concat(first, even_odd_cycle);
for (Foo& f : first_even_odd | views::take(N)) {
    // ...
}
eerorika
  • 232,697
  • 12
  • 197
  • 326
  • `cycle` and `take(N)` views were probably the crucial parts I was looking for to accomplish this task in a "ranges style" way. – cos Mar 24 '21 at 13:22
  • Here is the working example https://godbolt.org/z/1Y3hPrjeh – cos Mar 24 '21 at 14:25
  • Doesn't this get even and odd backwards, or is the OP counting starting with 1? – Yakk - Adam Nevraumont Mar 24 '21 at 17:10
  • @Yakk-AdamNevraumont Oh yea, this is reverse from OP's example of "first, odd, even, ...". I didn't pay enough attention to it and assumed that first is 1 and thus second is even. And that was the order of their variables too. Maybe it would be good to remove "even" and "odd" from variable names at which point it is fine to choose any order in the array without confusion. – eerorika Mar 24 '21 at 17:12
  • Can you, please, show, how to create a span over single object? If it's impossible to create vector – PolyGlot Apr 26 '22 at 10:35
  • 1
    @PolyGlot You can create a span of a single object like this: `std::span(&first, 1)` – eerorika Apr 26 '22 at 10:59
3

Start with a counting range; 0,1,2,3,4... iota is the (poorly named) name for this range.

Then transform by [&](auto n)->decltype(auto){return n?n%2?odd:even:first;}.

I think that is what want.

Further reading:

https://en.cppreference.com/w/cpp/ranges/iota_view

https://en.cppreference.com/w/cpp/algorithm/ranges/transform

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
1

You are making things to complicated. Just extract functions and you done:

void extractedFunction(Foo& foo);

void yourLogic(int N)
{
    Foo first, even, odd;
    extractedFunction(foo);
    for (int i = 0; i < (N - 1) / 2; ++i) {
        extractedFunction(odd);
        extractedFunction(even);
    }
    if ((N - 1) % 2 == 1) {
        extractedFunction(odd);
    }
}
Marek R
  • 32,568
  • 6
  • 55
  • 140
  • This doesn't seem to answer my question. I want a lightweight (references?) view for my objects, constructed with a certain pattern. I want to pass this view as a parameter as well. – cos Mar 24 '21 at 12:55
  • 1
    @cos please edit your question to make clear why this answer doesn't meet your needs. – Marek R Mar 24 '21 at 12:57
1

I think you need to create a container which value_type is pointer of Foo , like that vector<Foo*> ,than you can call views::indirect to get the reference to your original object. https://godbolt.org/z/9x84v4851

#include <range/v3/all.hpp>
#include <fmt/format.h>
#include <fmt/ranges.h>
namespace views =ranges::views;

int main()
{
  int first=0;
  int a =1, b=2;
  std::vector<int*> v{&a,&b};
  auto ra=v|views::cycle|views::take(8)|views::indirect;
  auto rf=views::single(&first)|views::indirect;
  auto res=views::concat(rf,ra);
  fmt::print("{}",res);

}
jiayuehua
  • 54
  • 1