首页 > 解决方案 > 使用“分组”元素迭代向量?

问题描述

考虑包装在同一个向量中的 4 种颜色的示例(设计的这一方面不能轻易更改 - 例如来自第三方):

std::vector rgb_colors = {1,1,1,2,2,2,3,3,3,4,4,4};

以下可以工作:

for (size_t ci = 0; ci + 2 < rgb_colors.size(); ci+=3) {
  auto& red_component = rgb_colors[ci];
  auto& green_component = rgb_colors[ci+1];
  auto& blue_component = rgb_colors[ci+2];
  //...
}

在真空中,这种方法足够“无辜”。但是,对于现代 c++/等,我通常会避开这种编码方法,因为它更脆弱/容易出错/冗余/等。现在更喜欢基于范围的 for 循环、迭代器等。

那么解决这个问题的更有表现力优雅的方法是什么?

更新: 添加了关于“数据布局”不能轻易更改的注释。

标签: c++rangeiterationc++17

解决方案


正如评论中提到的,创建一个struct表示颜色的颜色,或者更确切地说使用可能与您用于图形的任何库一起提供的颜色,以便您可以正确地与之交互:

struct color {
    int red, green, blue;
    // Add members as you see fit
};

std::vector rgb_colors = {color{1,1,1}, color{2,2,2}, color{3,3,3}, color{4,4,4}};
// or
// std::vector<color> rgb_colors = {{1,1,1}, {2,2,2}, {3,3,3}, {4,4,4}};

for (auto& c : rgb_colors) {
  auto& red_component = c.red;
  auto& green_component = c.green;
  auto& blue_component = c.blue;
  //...
}

或者,较少关注具体示例,您可以使用范围/迭代器适配器,例如boost::adaptors::stride

#include <boost/range/adaptor/strided.hpp>

//...

for (auto& c : boost::adaptors::stride(rgb_colors, 3)) {
  auto& red_component = (&c)[0];
  auto& green_component = (&c)[1];
  auto& blue_component = (&c)[2];
  //...
}

这仍然(如在您的示例中)要求您确保向量的长度可被整除3以避免 UB 并且元素std::vector首先是连续数组的一部分(如提供的那样),以便指针算术(&c)[i]具有定义明确的行为。


推荐阅读