7

ポリゴンのベクトルがあり、各ポリゴンにポイントのベクトルが含まれているとします。コード内のすべてのポリゴンのすべてのポイントを何度も繰り返す必要があり、同じコードを何度も書く必要があります。

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();
        }
}

これは2回の単純な反復では多くのコードであり、コードを詰まらせて読みやすさを妨げているように感じます。

私が思ったいくつかのオプションは次のとおりです。

  • #definesを使用します-ただし、移植性がなくなります(コードの他の部分で使用するため)。さらに、#definesは最近悪と見なされています。
  • vector-> size()を反復処理します-これは最もエレガントな方法ではないようです。
  • 関数ポインタを使用してメソッドを呼び出す-ただし、この場合、ループ内にあるはずのコードはループから遠くなります。

それで、これを行うための最もクリーンでエレガントな方法は何でしょうか?

4

7 に答える 7

24

C ++ 11では、ranged-baseforループautoキーワードを使用します。

for(const auto& polygon : polygons) {
    for(const auto& point : polygon->points) {
        point.DoSomething();
    }
}
于 2013-01-11T21:14:27.553 に答える
9

C ++ 11を使用できない場合、boostには多くのコードを生成するFOREACHマクロがありますが、コードは劇的に単純化されます。

BOOST_FOREACH(Polygon * polygon, polygons)
{
    BOOST_FOREACH( Point & point, polygon->points )
    {
        point.doSomething();
    }
}
于 2013-01-11T21:18:32.120 に答える
5

内側のループは、次のようなアルゴリズムを使用して書き直すことができます。

std::for_each(
    (*polygon)->points.begin(), (*polygon)->points.end(), 
    &Point::DoSomething
);

これを外側のループと混合するのは少し複雑です。

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

ある種の複合イテレータがあれば、実際にあなたの意図を表現することができます。それは、ポリゴンの各ポイントに対して何かを行うことです。また、Boost.Rangeのような範囲ライブラリを使用すると、範囲全体を操作する場合に、各コンテナに2回名前を付けることを回避できます。

あなたのコードの私の理想的なバージョンは次のようになります:

for_each( flatten( polygons ), &Point::DoSomething );

まるでそれが単一の連続した範囲であるかのように、すべてのすべてのビューflattenを返します。これはプレーンなC++03で実現できるものであり、 Boost.Rangeに欠けているのは範囲を平坦化することだけであり、範囲の観点から実装するのは難しいことではないことに注意してください。PointPolygonjoin

それ以外の場合は、範囲ベースのforループを一緒に使用autoすると、範囲をスローして複雑なタイプを忘れるという反復の定型文を減らすことができます。

于 2013-01-11T21:17:41.427 に答える
5

C ++ 11を使用できない場合は、イテレータタイプを次のような短いものにtypedefします。

typedef std::vector<Polygon*>::const_iterator PolyCit;
for (PolyCit polygon = polygons.begin(); polygon != polygons.end(); polygon++)
于 2013-01-11T21:17:48.670 に答える
1

気にしないでください。トップレベルにポインタのベクトルがあるため、これは機能しませんが、かなりクールだと思うので、これを維持します。


私のテンプレートメタプログラミングは少し錆びているので、これを行うためのより簡単な方法があるかもしれませんが、:

template<typename C, typename F, size_t depth>
struct nested_for_each_helper
{
    static void do_it(C& c, F& f)
    {
        for (auto& i : c)
            nested_for_each_helper<decltype(i),F,depth-1>::do_it(i,f);
    }
};

template<typename C, typename F>
struct nested_for_each_helper<C,F,0>
{
    static void do_it(C& c, F& f)
    {
        f(c);
    }
};

template<size_t depth, typename C, typename F>
void nested_for_each(C& c, F& f)
{
    nested_for_each_helper<C,F,depth>::do_it(c,f);
}

int main()
{        
    int n[3][3][3][3];
    int i = 0;
    nested_for_each<4>(n,[&i](int& n) { n = i++; });
    nested_for_each<4>(n,[](int n){
        std::cout << n << ' ';
    });
}

あなたの場合、あなたはそれをこのように使うことができます(あなたはそうすることができません):

nested_for_each<2>(polygons, [](Point const& p) { p.DoSomething(); });
于 2013-01-11T21:28:29.283 に答える
1

抽象化レイヤーが必要です。ポリゴンのベクトルを処理する代わりに、そのベクトルを管理するクラスを作成します。次に、クラスは、ポイントを反復処理するための反復子ペアを提供します。イテレータのコードは、これらの詳細を認識してカプセル化します。

于 2013-01-11T21:28:30.030 に答える
0

まず第一に、昔ながらの整数ベースのループがあります。イテレータより少し短いです。

for( int i = 0 ; i < polygons.size() ; i++ )
{
    for( int j = 0 ; j < polygons[i]->points.size(); j++)
    {
        Point* p = polygons[i]->points[j] ;
        p->DoSomething();
    }
}

それが気に入らず、C ++ 11が利用できない場合は、ファンクターを受け入れる関数を作成できます(これらはC ++ 0xであったstd::tr1と思います)。

void eachPoint( function<void (Point* p)> func )
{
    for( int i = 0 ; i < polygons.size() ; i++ )
    {
        for( int j = 0 ; j < polygons[i]->points.size(); j++)
        {
            Point* p = polygons[i]->points[j] ;
            func(p);
        }
    }
}

または、単純な古いマクロ:

#define EACH_POLYGON( polyCollection ) for( int _polyI = 0 ; _polyI < polyCollection.size() ; _polyI++ ) \
for( int _ptNo = 0, Point* p=polyCollection[_polyI]->points[0] ; j < polyCollection[_polyI]->points.size() && (p=polyCollection[_polyI]->points[_ptNo]); _ptNo++)

EACH_POLYGON( polyCollection )
{
    p->DoSomething();
}
于 2013-01-11T21:37:47.160 に答える