Home > Back-end >  Using C 20 Ranges to Avoid Loops
Using C 20 Ranges to Avoid Loops

Time:10-06

I was assigned a task where I need to solve a problem given several constraints. The point is to enforce the use of STL algorithms, iterators, and new c 20 functionality including things like ranges. However I've been reading on ranges for hours and I still can't figure out how I can implement the problem given all the constraints. I've simplified the problem and removed the specific details to make it more generic.

The Problem:

Write a function that 1) takes in a vector of custom objects input 2) returns a vector of a different type that includes an element for each object in input that satisfies some conditions. The value added is based on the properties of the input objects.

I realize this may sound obscure so here's a simple example. For an input vector of Shapes where each has a name and an area:

vector<Shapes> input{ { "Square", 10 }, { "Triangle", 30 } , { "Square", 1 }, { "Circle", 30 }, { "Triangle", 15 } };

return a vector of enums

enum Color { RED, BLUE, GREEN };

such that an enum is added for each Square or Circle. The value of the enum is determined based on the area of each Shape. So, let's say, if the area is above 20, RED is added, otherwise, GREEN is added.

So in this case we'd return { GREEN, GREEN, RED }

This is all well and good and could be implemented in a myriad of ways, what makes it very difficult are the constraints.

The Constraints:

  • no loops or recursion
  • no std::for_each
  • no data structures other than std::vector
  • no memory allocation (other than a one-time allocation for the return vector)
  • no by-reference lambda captures or mutable lambdas
  • cannot modify the input vector

My professor claims that "c 20 ranges make this task particularly simple." But even after reading on ranges for hours I'm not even sure where would I begin. My current train of thought is to create a std::view and filter it based on the conditions (Squares & Circles) but then I'm not sure how I would create a new vector of a different type and add elements to it based on the properties of the elements in the view without using loops, for_each, or by-reference lambdas..

CodePudding user response:

If you simply want to transform every shape to an enum, all you need is:

auto colors = input | transform([](const Shapes& s){return s.size > 20 ? RED : GREEN;});

colors can then be looped through in a for-loop:

for (const auto& c : colors)

Or be made into a new vector:

std::vector<Color> colorEnums{colors.begin(), colors.end()};

...though C 23's ranges_to would be helpful for the latter.

If you want to only generate the color elements for some elements in your input vector (ex.: not triangles), add filter before transform, e.g.:

auto colors = input | 
    filter([](const Shapes& s){return s.type != "Triangle";}) | 
    transform([](const Shapes& s){return s.size > 20 ? RED : GREEN;});

Note that having filter after transform would work too, but be less efficient, as the code would then transform all elements, before discarding some of them. So use filter as early as possible.

  • Related