C++11中的foreach语法和自定义迭代器

60

我正在为一个被用作STL容器替代品的容器编写迭代器。目前,许多地方都使用了STL容器并使用c++11 foreach语法,例如:for(auto &x: C)。我们需要更新代码以使用包装STL容器的自定义类:

template< typename Type>
class SomeSortedContainer{
    std::vector<typename Type> m_data; //we wish to iterate over this
    //container implementation code
};    
class SomeSortedContainerIterator{
    //iterator code
};

如何让auto使用正确的迭代器来遍历自定义容器,以便代码能够按以下方式调用:

SomeSortedContainer C;
for(auto &x : C){
    //do something with x... 
}

一般而言,如何确保auto使用一个类的正确迭代器?


如果您正在使用Visual Studio,则可以将鼠标悬停在变量名称上以查看其类型。如果我没记错的话,它会显示实际类型,而不是“auto”。 - Cole Tobin
4个回答

53
为了能够使用基于范围的for循环,你的类应该提供const_iterator begin() constconst_iterator end() const成员函数。你也可以重载全局的begin函数,但我认为拥有一个成员函数会更好。iterator begin()const_iterator cbegin() const也是推荐的,但不是必须的。如果你只想遍历一个内部容器,那么这非常简单:
template< typename Type>
class SomeSortedContainer{

    std::vector<Type> m_data; //we wish to iterate over this
    //container implementation code
public:
    typedef typename std::vector<Type>::iterator iterator;
    typedef typename std::vector<Type>::const_iterator const_iterator;

    iterator begin() {return m_data.begin();}
    const_iterator begin() const {return m_data.begin();}
    const_iterator cbegin() const {return m_data.cbegin();}
    iterator end() {return m_data.end();}
    const_iterator end() const {return m_data.end();}
    const_iterator cend() const {return m_data.cend();}
};    
如果你想迭代任何自定义的东西,那么你可能需要在容器内设计自己的迭代器类。
class const_iterator : public std::iterator<random_access_iterator_tag, Type>{
    typename std::vector<Type>::iterator m_data;
    const_iterator(typename std::vector<Type>::iterator data) :m_data(data) {}
public:
    const_iterator() :m_data() {}
    const_iterator(const const_iterator& rhs) :m_data(rhs.m_data) {}
     //const iterator implementation code
};

想要了解如何编写迭代器类的更多细节,请参阅我的答案


52
您有两个选择:
  • 提供名为beginend的成员函数,并且可以像调用C.begin()C.end()一样调用它们;
  • 否则,您可以提供名为beginend的自由函数,这些函数可以使用参数相关查找或者在std名称空间中找到,并且可以像调用begin(C)end(C)一样调用它们。

2
请参阅Stroustrup的C++11 FAQ,详细了解"Range-for"语句(包括成员/函数优先级)的描述。 - rluba

8

正如其他人所说,您的容器必须实现begin()end()函数(或者具有全局或std::函数,这些函数以您的容器实例作为参数)。

这些函数必须返回相同的类型(通常为container::iterator,但这只是一种约定)。返回的类型必须实现operator*operator++operator!=


2
据我所知,SomeSortedContainer 只需要提供 begin()end() 方法。这些方法应该返回符合标准的前向迭代器,在您的情况下是 SomeSortedContainerIterator,它实际上会包装一个 std::vector<Type>::iterator。符合标准指它必须提供通常的增量和解引用操作符,但也必须提供所有这些 value_typereference_type 等类型定义,这些类型定义反过来又被 foreach 结构用于确定容器元素的基础类型。但您也可以直接从 std::vector<Type>::iterator 中转发它们。

3
如果缺少 beginend 成员函数,则 foreach 也可以使用 beginend 非成员函数。 - user802003
@Mike 你是说以容器作为单一参数的自由函数吗?不错,我不知道呢。 我想这对于扩展现有的容器类很有用。 - Christian Rau

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