公开多个可迭代接口

时间:2011-11-04 13:02:05

标签: c++ loops

Scene包含Shape的列表。

每个Shape都包含:

  • std::vector Vertex(表面法线,texcoord,3空间位置)
  • std::vector Triangle(绑定顶点,用于网格交叉)

我想将Scene对象可迭代两者作为Vertex的集合,以及Triangle的集合,在中不那么凌乱的方式。

目前需要的是走三角形:(这里是C#语法):

foreach( Shape shape in Scene )
{
    foreach( Mesh mesh in shape.meshGroup.meshes )
    {
        foreach( Triangle tri in mesh.tris )
        {
            // work with tri
        }
    }
}

三重嵌套for不好看,当然C ++语法更糟糕,使用计数器i,j和k或使用::iterator s ..

要访问每个Vertex

foreach( Shape shape in Scene )
{
    foreach( Mesh mesh in shape.meshGroup.meshes )
    {
        foreach( Vertex v in mesh.verts )
        {
            // work with v
        }
    }
}

由于从开始走所有三角形/顶点是昂贵的,最好的方法是什么? (假设有必要点击每个 Triangle / Vertex,因此不需要空间细分算法等)

您可以使用任何C ++ 0x功能(启用VS-2010),包括lambda。

3 个答案:

答案 0 :(得分:2)

您可以创建迭代所有元素并调用函数对象的函数:

template <typename F>
inline void for_each_vertex(Scene& scene,F f)
{
  for (Shape& shape : scene) {
    for (Mesh& mesh : shape.meshGroup.meshes) {
      for (Vertex& vertex : mesh.verts) {
        f(vertex);
      }
    }
  }
}

template <typename F>
inline void for_each_triangle(Scene& scene,F f)
{
  for (Shape& shape : scene) {
    for (Mesh& mesh : shape.meshGroup.meshes) {
      for (Triangle& triangle : mesh.tris) {
        f(triangle);
      }
    }
  }
}

现在你可以做到

for_each_vertex(scene,[](Vertex& vertex)(/* work with vertex */});
for_each_triangle(scene,[](Triangle& triangle)(/* work with triangle */});

这应该与原始代码具有相同的性能,但您不必在整个程序中多次编写相同的循环结构。

答案 1 :(得分:0)

如果所有处理都在内部循环中完成,则可以创建一个自定义迭代器,它迭代所有三个级别,并生成(Shape*,Mesh*,Vertex*)三元组,处理移动的逻辑,例如在为当前Mesh迭代所有Vertex es后,转到下一个Mesh

如果你想在中间或外部循环中进行某些处理,你可以添加一些钩子,或者例如第一次通过新的{{(Shape*,NULL,NULL)三元组返回Shape三元组。 1}}。

答案 2 :(得分:0)

我通常做的是将单独的“逻辑容器”暴露给一个大(多)容器类:

我定义了一个方法'getMeshRange(), getShapeRange()`等。

如果您使用提升范围库,则可以返回boost::iterator_range<const Shape*>boost::sub_range<std::vector<Vertex> >等。

在实践中,IIRC,为了满足范围概念,您只需返回std::pair<const_iterator, const_iterator>

范围可以如下使用:

for (It it = std::begin(X.getMeshRange()); it!= std::end(X.getMeshRange()); ++it)
{ 
    // use *it
}

或在C ++ 0x中

for (auto& mesh : X.getMeshRange())
{
    // use mesh
}

使用Boost Range算法,您可以使用“常规”容器执行任何操作:

const Shape& shape = *std::min_element(X.getShapeRange());