C++11:模板化迭代器描述的基于范围的 for 循环



在我的C++03代码中,我有很多看起来像这样的函数:

class A {
public:
    template <Iterator>
    void doSomethingWithObjects(Iterator begin, Iterator end) {
        for (Iterator point = begin; point != end; point++) {
            mInternal.doSomething(*point);
        }
    }
private:
    DataStructure mInternal;
};

我正在尝试在新代码中尽可能多地使用 C++11 的功能,特别是基于范围的 for 循环。我的问题是,我将如何使用模板化迭代器执行此操作?是否有一个魔术C++结构,它采用两种模板化迭代器类型,并将它们转换为范围表达式?换句话说,我正在寻找这样的东西:

class A {
public:
    template <Iterator>
    void doSomethingWithObjects(Iterator begin, Iterator end) {
        static_assert(std::is_same<Point, typename std::decay<Iterator>::type>::value, "wrong type mate!"); // extra credit
        for (auto&& point : std::magic(begin, end)) {
            mInternal.doSomething(point);
        }
    }
private:
    DataStructure mInternal;
};

如果在 C++11 中有一种新的、首选的方法来执行这种"向此结构添加许多对象",我也会全神贯注。

标准库中没有任何内容。Boost有make_iterator_range,其简化版本写起来很简单:

template<class Iterator>
struct iter_range {
    Iterator begin_, end_;
    Iterator begin() const { return begin_; }
    Iterator end() const { return end_; }
};
template<class Iterator>
iter_range<Iterator> make_range(Iterator b, Iterator e) { return {b, e}; }

最初的问题只是叫push_back.为此,它不需要循环。只需使用 insert 的 C++03 范围过载:

mInternal.insert(mInternal.end(), begin, end);
template<class It>
struct range_t {
  It b; It e;
  It begin() const { return b; }
  It end() const { return e; }
};
template<class It>
range_t<It> range( It b, It e ) {
  return {std::forward<It>(b), std::forward<It>(e)};
}

然后:

template <Iterator>
void doSomethingWithObjects(Iterator begin, Iterator end) {
    for (auto&& point : range(begin, end)) {
        mInternal.doSomething(point);
    }
}

鲍勃是你的叔叔。

"Range-v3"是一个正在经历标准化过程的库,已经包含了这样的东西。 Boost也有类似的机制。

但是这种事情很简单,可以自己滚,忘记它。 (更好的版本包括empty,有条件地支持size[],可以从容器和C数组以及任何可迭代的东西构造,知道它们是否是相邻的,有条件地存储传入容器的副本以延长引用寿命等:但你真的不需要这些(。

我会添加一个函数重载并保留现有函数,以使过渡渐进且破坏性较小。

template <typename Container>
void doSomethingWithObjects(Container&& c) {
    for (auto&& item: c) {
        mInternal.doSomething(item);
    }
}

你实际上不需要把它们变成任何东西。只需将迭代器与std::for_each一起使用:

template <Iterator>
void doSomethingWithObjects(Iterator begin, Iterator end) {
    std::for_each(begin, end, [this](auto&& point){
        mInternal.doSomething(point);
    }
    // C++11 version
    std::for_each(begin, end, [this](decltype(*begin)& point) {
        mInternal.doSomething(point);
    }
}

或者编写简单的循环:

template <Iterator>
void doSomethingWithObjects(Iterator begin, Iterator end) {
    for (; begin != end; ++begin) {
        mInternal.doSomething(*begin);
    }
}

最新更新