构造一个可以使用基于范围的for循环进行迭代的对象。

3
我写了一个简短的实用函数,可以“包装”可迭代容器,以便我可以使用基于范围的 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 进行迭代? 应该如何最好地解决这个问题?


+1 我认为这将成为一个有用的标准组件。 - emsr
只需将其称为“reversed”,即可获得类似Python的函数:p - Morwenn
1
我已经编辑了我的答案,使用完美转发和函数rbeginrend来完善它,以求完整性。 - Morwenn
2个回答

4
选择可迭代对象的beginend函数的实际规则是:如果有类的beginend函数,则使用它们。如果提供了全局函数std::beginstd::end的重载,则使用这些重载。

静态数组不是类/结构体,因此它们没有成员函数。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
似乎std::rbeginstd::rend不存在。 - OmnipotentEntity
@OmnipotentEntity 是的,我意识到了。我会进行编辑,以便读者不会感到困惑。 - Morwenn
POD可以有成员函数,但不能是虚函数。 - ildjarn

2
在您的代码中,Iterable模板参数需要具有beginend成员函数。普通的C++数组没有这些函数。相反,您必须使用std::beginstd::end,它们是C++11标准的一部分。
然而,似乎没有任何std::rbeginstd::rend函数,这意味着您必须自己实现它们,可能还要实现实际的迭代器类。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接