4

を含むコンテナ、 を含むintコンテナ上で機能する関数Point、およびいくつかのint与えられた対応するものを与える関数があるPointとします(大きな でシーン内のすべてのポイントにインデックスを付けたと想像してくださいstd::vector<Point>)。コンテンツをコピーせずに最初のコンテナーを使用するための単純な (かつ効率的な) ラッパーを作成するにはどうすればよいですか?

入力したいコードは次のようなものです。

template<typename InputIterator>
double compute_area(InputIterator first, InputIterator beyond) {
    // Do stuff
}

template<typename InputIterator, typename OutputIterator>
void convex_hull(InputIterator first, InputIterator beyond, OutputIterator result) {
    // Do stuff
}

struct Scene {
    std::vector<Point> vertices;

    foo(const std::vector<int> &polygon) {
        // Create a simple wraper with limited amount of mumbo-jumbo
        auto functor = [](int i) -> Point& { return vertices[polygon[i]]; });
        MagicIterator polyBegin(0, functor);
        MagicIterator polyEnd(polygon.size(), functor);
        // NOTE: I want them to act as random access iterator

        // And then use it directly
        double a = compute_area(polyBegin, polyEnd);

        // Bonus: create custom inserter similar to std::back_inserter
        std::vector<int> result;
        convex_hull(polyBegin, polyEnd, MagicInserter(result));
    }
};

ご覧のとおり、少し一般的なものを探しています。私もラムダを使うことを考えましたが、シンプルで使いやすいものにするにはどうすればよいか、少し混乱しています。

4

2 に答える 2

3

Boost の Transform Iteratorをお勧めします。使用例を次に示します。

#include <boost/iterator/transform_iterator.hpp>
#include <vector>
#include <cassert>
#include <functional>

struct Point { int x, y; };

template<typename It>
void compute(It begin, It end)
{
    while (begin != end) {
        begin->x = 42;
        begin->y = 42;
        ++begin;
    }
}

int main()
{
    std::vector<Point> vertices(5);
    std::vector<int> polygon { 2, 3, 4 };

    std::function<Point&(int)> functor = [&](int i) -> Point& { return vertices[i]; };

    auto polyBegin = boost::make_transform_iterator(polygon.begin(), functor);
    auto polyEnd = boost::make_transform_iterator(polygon.end(), functor);

    compute(polyBegin, polyEnd);
    assert(vertices[2].y == 42);
}

custom についてはよくわかりませんでしたback_inserter。vectorに格納されている型resultが functor が返すものと同じである場合、標準ライブラリの型が機能します。それ以外の場合は、ラップすることもできtransform_iteratorます。

ファンクタは に格納されていることに注意してくださいstd::function。Boost はファンクタに依存して typedef がresult_type定義されており、ラムダにはそれがありません。

于 2013-08-12T18:32:35.253 に答える
1

2つの方法があります。から始めてboost::iterator_facade、「関数イテレータ」タイプを記述します。

または、 boost::counting_iteratorイテレータを使用するか、独自に作成し (非常に簡単です)、 を使用してそのイテレータをイテレータboost::transform_iteratorにマップします。IndexPoint

上記のすべては、直接記述することもできます。私はこれをランダム アクセス イテレータとして記述します。これには、多数typedefの 、++--多数の+=-=-+比較、および*->適切に定義されている必要があります。これはちょっとしたボイラープレートです。boost上記のライブラリは、ボイラープレートを少し減らしただけです (ボイラープレートをそれ自体の中に持つことによって)。

関数の型を引数として取り、関数をインデックスと一緒に格納するバージョンを自分で作成しました。インデックスを使用して前進/比較/etc し、関数型を使用して逆参照します。関数の型std::function<blah()>を作成することで、型が消去されたバージョンを取得しdecltype、ラムダ引数またはファンクターの型にすることで、より効率的なバージョンを取得します。

于 2013-08-12T18:52:47.053 に答える