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

所以,正如你所看到的,我正在寻找一些通用的东西。我也考虑过使用 lambdas,但我对如何继续保持简单和用户友好有点困惑。

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。如果result向量中存储的类型与仿函数返回的类型相同,则标准库中的类型将执行此操作。否则你也可以把它包起来transform_iterator

请注意,函子存储在std::function. Boost 依赖函子来result_type定义 typedef,而 lambdas 没有。

于 2013-08-12T18:32:35.253 回答
1

我看到了两种方法。要么以 开头boost::iterator_facade,然后编写“功能迭代器”类型。

或者,使用 boost::counting_iterator迭代器或自己编写(它们很容易),然后使用将该迭代器boost::transform_iterator映射到您的迭代器。IndexPoint

以上都可以直接写。我会把它写成一个随机访问迭代器:它需要一些typedefs, ++, --, 一些+=, -=, -, +s, 比较, and*->正确定义。它有点像样板文件,boost上面的库只是让它变得更少样板文件(通过在其内部包含样板文件)。

我为自己编写了一个版本,它将函数类型作为参数,然后将函数与索引一起存储。它使用索引推进/比较/等,并使用函数类型取消引用。通过创建函数类型std::function<blah()>,我得到了它的类型擦除版本,并通过将其decltype设为 lambda 参数或仿函数的类型,我得到了更有效的版本。

于 2013-08-12T18:52:47.053 回答