【问题标题】:C++11: Range-based for loop over range described by templated iteratorsC++11:模板化迭代器描述的基于范围的 for 循环
【发布时间】:2015-11-20 21:30:23
【问题描述】:

在我的 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 中有一种新的、首选的方法来执行这种“向这个结构中添加许多对象”,我也很乐意。

【问题讨论】:

  • 你的意思是this?
  • 是的,完全正确!是否有一个 std 结构可以做到这一点?
  • 不,据我所知,在 C++11 和 C++14 的标准库中没有类似的东西

标签: c++ c++11 for-loop iterator


【解决方案1】:

标准库中什么都没有。 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);

【讨论】:

  • 编辑澄清有时我会做计算等等,而不仅仅是插入。
  • 谢谢,我使用 boost,所以这可能是我最好的选择!
【解决方案2】:
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数组以及任何可迭代的东西构造,知道它们是否是连续的,有条件地存储传入容器的副本以延长引用寿命等: 但你真的不需要这些)。

【讨论】:

  • 谢谢,很有帮助!
【解决方案3】:

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

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

【讨论】:

  • 谢谢,非常有帮助!唯一的问题当然是如果你想传递一个数组,这有时会发生在我的代码中。
  • @bombax,对于该用例,使用其他答案建议的 range_t 对象将派上用场。
【解决方案4】:

您实际上不需要将它们变成任何东西。只需将迭代器与 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);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-08
    • 2022-01-14
    相关资源
    最近更新 更多