在C++中迭代的优雅方式

And*_*ner 7 c++ coding-style vector

假设我有一个多边形矢量,其中每个多边形包含一个点矢量.我必须在我的代码中多次迭代所有多边形的所有点,我最终不得不一遍又一遍地编写相同的代码:

for(std::vector<Polygon*>::const_iterator polygon = polygons.begin();
                polygon != polygons.end(); polygon++)
{
        for(std::vector<Point>::const_iterator point = (*polygon)->points.begin();
                        point != (*polygon)->points.end(); point++)
        {
                (*point).DoSomething();
        }
}
Run Code Online (Sandbox Code Playgroud)

我真的觉得这是两个简单迭代的很多代码,感觉它堵塞了代码并干扰了可读性.

我认为有些选择:

  • 使用#defines - 但它会使得不可移植(在代码的其他部分使用).此外,#define现在被认为是邪恶的;
  • 迭代vector-> size() - 它似乎不是最优雅的方式;
  • 使用函数指针调用方法 - 但在这种情况下,应该在循环内部的代码远离循环.

那么,这样做最干净,最优雅的方式是什么?

Rob*_*obᵩ 24

在C++ 11中,使用基于范围的for循环auto关键字:

for(const auto& polygon : polygons) {
    for(const auto& point : polygon->points) {
        point.DoSomething();
    }
}
Run Code Online (Sandbox Code Playgroud)


pel*_*tjl 9

如果你不能使用C++ 11,boost有一个FOREACH宏,可以生成大量的代码,但会大大简化你的代码:

BOOST_FOREACH(Polygon * polygon, polygons)
{
    BOOST_FOREACH( Point & point, polygon->points )
    {
        point.doSomething();
    }
}
Run Code Online (Sandbox Code Playgroud)


K-b*_*llo 5

可以使用以下算法重写内部循环:

std::for_each(
    (*polygon)->points.begin(), (*polygon)->points.end(), 
    &Point::DoSomething
);
Run Code Online (Sandbox Code Playgroud)

将它与外部循环混合有点复杂:

std::for_each(
    polygons.begin(), polygons.end(),
    []( Polygon* polygon ) {
        std::for_each(
            polygon->points.begin(), polygon->points.end(), 
            &Point::DoSomething
        );
    }
);
Run Code Online (Sandbox Code Playgroud)

如果我们有某种复合迭代器,我们可以真正表达你的意图,即为每个多边形中的每个一些事情.并且像Boost.Range这样的范围库允许您避免将每个容器命名两次,因为您希望使用它们的整个范围.

我理想的代码版本如下所示:

for_each( flatten( polygons ), &Point::DoSomething );
Run Code Online (Sandbox Code Playgroud)

分别flatten将返回一个视图的每一个Point在每一个Polygon,就好像它是一个单一的连续范围.请注意,这可以在普通的C++ 03中实现,而我们在Boost.Range中缺少的所有内容都是一个扩展范围,在范围方面应该不难实现join.

否则,范围为基础的循环一起auto将帮助您减少迭代的样板抛出一个范围,忘掉复杂的类型.


小智 5

如果你不能使用C++ 11,也许可以将迭代器类型定义为更短的类似

typedef std::vector<Polygon*>::const_iterator PolyCit;
for (PolyCit polygon = polygons.begin(); polygon != polygons.end(); polygon++)
Run Code Online (Sandbox Code Playgroud)