使用C++20范围避免循环

6
我被分配了一个任务,需要在给定多个约束条件的情况下解决问题。目的是强制使用STL算法、迭代器和新的C++20功能,其中包括像ranges这样的东西。然而我已经阅读了几个小时有关ranges的资料,但仍然无法弄清楚如何实现所给出的所有约束条件下的问题。我简化了问题并删除了具体细节,以使其更加通用。
问题:
编写一个函数,该函数 1) 接受自定义对象向量input 2)返回一个包含每个满足某些条件的对象对应值的不同类型向量。
我意识到这可能听起来很模糊,这里有一个简单的例子:对于一个形状(Shapes)的输入向量,每个形状都有一个名称和一个面积。
vector<Shapes> input{ { "Square", 10 }, { "Triangle", 30 } , { "Square", 1 }, { "Circle", 30 }, { "Triangle", 15 } };

返回一个枚举向量

enum Color { RED, BLUE, GREEN };

为了使每个正方形或圆形的面积基于其面积确定枚举的值。 因此,假设如果面积大于20,则添加RED,否则添加GREEN。 因此,在这种情况下,我们将返回{ GREEN,GREEN,RED }。
这很好理解并且可以用多种方法实现,但是约束条件使其非常困难。
约束条件:
- 没有循环或递归 - 没有std::for_each - 除std::vector之外没有其他数据结构 - 除一次性为返回向量分配内存之外,没有其他内存分配 - 没有通过引用的lambda捕获或可变lambda - 不能修改输入向量
我的教授声称“C ++ 20范围使这个任务特别简单。”但是即使阅读了几个小时的范围,我也不确定从哪里开始。 我目前的思路是创建一个std :: view并根据条件(正方形和圆形)进行过滤,但是我不确定如何创建一个新的不同类型的向量,并根据视图中元素的属性将元素添加到其中,而不使用循环,for_each或通过引用的lambda ......

2
“我目前的想法是创建一个std::view,并根据条件进行过滤。” 请参考cppreference的示例,创建一个需要传递views::filter和views::transform的lambda函数。 - 康桓瑋
@康桓瑋,我已经仔细阅读了文档,并通过使用std::views::filter和创建lambda函数来创建了一个过滤器视图,其中包含满足条件的输入向量元素。 接下来的部分是我卡住的地方... - Adham
你需要使用 rangess::to_vector(它是通过 for 循环实现的)将你过滤和转换后的范围转换为向量,因为 c++20 不提供这个功能(只有在 c++23 中才有)。你必须使用 range-v3 或使用 for 循环。for 循环总是存在于某个地方,ranges 很好,因为它们将它们推入到你不必担心的代码中。 - Tom Huntington
@康桓瑋,哇,它实际上比我预想的要简单得多。我想我没有想到views::transform也可以转换视图元素的数据类型。经过转换后,我只需要使用生成的视图的beginend迭代器创建一个向量(正如@cptFracassa在他的答案中所说)就行了,结果很棒。感谢你的支持。 - Adham
1
我第一次看到一位C++教授要求学生使用STL而不是编写C代码。祝贺他! - Enlico
显示剩余8条评论
1个回答

10

如果你只想将每个形状转换为一个枚举,你所需要的就是:

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

可以通过for循环遍历colors

for (const auto& c : colors)

也可以将其转化为新的向量:

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

不过,对于后者,C++23中的ranges::to会很有帮助。

如果您只想为输入向量中的某些元素生成颜色元素(例如:不是三角形),在转换之前添加筛选器,例如:

auto colors = input | 
    filter([](const Shapes& s){return s.type != "Triangle";}) | 
    transform([](const Shapes& s){return s.size > 20 ? RED : GREEN;});
请注意,在转换后使用过滤器也可以起作用,但效率会更低,因为代码会在丢弃某些元素之前转换所有元素。因此,请尽早使用过滤器。

请注意,在转换后使用过滤器也可以起作用,但效率会更低,因为代码会在丢弃某些元素之前转换所有元素。因此,请尽早使用过滤器。


我接受这个答案,因为它正确地展示了第二步(views::transform)和第三步(使用视图的迭代器创建输出向量)。我只想指出,如@康桓瑋在评论中所指出的那样,先前的第一步将是根据给定条件过滤输入数组。谢谢! - Adham
1
@Adham 在你写评论的时候,我已经添加了过滤器 :-) - cptFracassa
1
太棒了!希望它能帮助其他陷入同样困境的人:D。我现在有点理解ranges周围的炒作了。 - Adham
@Jarod42 看来我没有仔细阅读文本。我现在已经更改了示例。 - cptFracassa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接