构造一个可以使用基于的范围迭代的对象

时间:2012-07-20 13:59:25

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

我写了一个简短的实用程序函数,一个对象来“包装”一个可迭代的容器,这样我就可以使用基于for的范围向后移动它。

template <typename Iterable>
struct ReverseWrapper {
private:
  Iterable& m_iterable;

public:
  ReverseWrapper(Iterable& iterable) : m_iterable(iterable) {}

  auto begin() const ->decltype(m_iterable.rbegin()) {
    return m_iterable.rbegin();
  }

  auto end() const ->decltype(m_iterable.rend()) {
    return m_iterable.rend();
  }
};

template <typename Iterable>
ReverseWrapper<Iterable> reverseIterate(Iterable& list) {
  return ReverseWrapper<Iterable>(list);
}

这适用于C ++可迭代对象,但不适用于静态数组。使用基于范围for的对象支持迭代需要什么?解决这个问题的最佳方法是什么?

2 个答案:

答案 0 :(得分:4)

为iterables选择beginend函数的实际规则如下:如果它有一些,请使用类beginend函数。如果提供了一些函数,请使用全局函数std::beginstd::end的重载。

静态数组不是class / struct,它们没有/不能有成员函数。 foreach循环调用的函数是全局函数std::beginstd::end,将数组作为参数。假设存在std::rbeginstd::rend,则必须按以下方式构建包装器:

template <typename Iterable>
struct ReverseWrapper {
private:
  Iterable& m_iterable;

public:
  ReverseWrapper(Iterable&& iterable) : m_iterable(iterable) {}

  auto begin() const -> decltype(rbegin(m_iterable)) {
    return rbegin(m_iterable);
  }

  auto end() const -> decltype(rend(m_iterable)) {
    return rend(m_iterable);
  }
};

template<typename Iterable>
auto reverseIterate(Iterable&& list)
    -> ReverseWrapper<Iterable>
{
    return ReverseWrapper<Iterable>(std::forward<Iterable>(list));
}

尽管c ++ 14标准中存在std::rbeginstd::rend,但它们在c ++ 11中并不可用。因此,要使上述代码与c ++ 11一起使用,您必须手动实现这些功能:

template<typename T, std::size_t N>
auto rbegin(T (&array)[N])
    -> std::reverse_iterator<T*>
{
    return std::reverse_iterator<T*>(std::end(array));
}

template<typename T, std::size_t N>
auto rend(T (&array)[N])
    -> std::reverse_iterator<T*>
{
    return std::reverse_iterator<T*>(std::begin(array));
}

答案 1 :(得分:2)

在您的代码中,Iterable模板参数需要具有beginend成员函数。普通C ++数组没有这些功能。相反,您必须使用std::beginstd::end,它们是C ++ 11标准的一部分。

但是,似乎没有任何std::rbeginstd::rend函数,这意味着您必须自己实现这些函数,也可能实现实际的迭代器类。