2011-09-26 40 views
57

Tôi đang viết một iterator cho một container đang được sử dụng thay cho một container STL. Hiện tại, hộp chứa STL đang được sử dụng ở nhiều nơi với c++11 foreach syntax ví dụ: for(auto &x: C). Chúng tôi đã cần thiết để cập nhật mã sử dụng một lớp tùy chỉnh mà kết thúc tốt đẹp container STL:C++ 11 foreach cú pháp và tùy chỉnh iterator

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

Làm thế nào để có được tự động sử dụng iterator chính xác cho container tùy chỉnh để mã có thể được gọi theo trình sau cách ?:

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

Nói chung cần phải đảm bảo tự động sử dụng trình lặp vòng chính xác cho một lớp học?

+0

Nếu bạn đang sử dụng Visual Studio, bạn có thể di chuột qua tên của biến để xem loại của nó. IIRC, nó cho thấy loại thực tế, không phải 'tự động'. –

Trả lời

50

Bạn có hai lựa chọn:

chức năng thành viên
  • bạn cung cấp tên beginend có thể được gọi như C.begin()C.end();
  • nếu không, bạn cung cấp các chức năng miễn phí có tên beginend có thể tìm thấy bằng tra cứu phụ thuộc vào đối tượng hoặc trong không gian tên std và có thể được gọi là begin(C)end(C).
+2

Xem Câu hỏi thường gặp [C++ 11 của Stroustrup] (http://www.stroustrup.com/C++11FAQ.html) để biết mô tả chi tiết về câu lệnh [Phạm vi cho "] (http: //www.stroustrup) .com/C++ 11FAQ.html # for) (bao gồm ưu tiên thành viên/chức năng). – rluba

50

Để có thể sử dụng dựa trên dải ô, lớp học của bạn nên cung cấp const_iterator begin() constconst_iterator end() const thành viên. Bạn cũng có thể quá tải chức năng toàn cầu begin, nhưng có một chức năng thành viên là tốt hơn theo ý kiến ​​của tôi. iterator begin()const_iterator cbegin() const cũng được đề xuất nhưng không bắt buộc. Nếu bạn chỉ muốn để lặp qua một container nội duy nhất, đó là thực sự dễ dàng:

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();} 
};  

Nếu bạn muốn để lặp qua bất cứ điều gì tùy chỉnh tuy nhiên, có thể bạn sẽ phải thiết kế vòng lặp của riêng bạn như các lớp bên trong container của bạn.

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 
}; 

Để biết thêm chi tiết về cách viết lớp lặp, xem my answer here.

2

Kiến thức của tôi SomeSortedContainer chỉ cần cung cấp begin()end(). Và những điều này sẽ trả lại trình lặp chuyển tiếp tuân thủ chuẩn, trong trường hợp của bạn là SomeSortedContainerIterator, thực tế sẽ bao bọc std::vector<Type>::iterator. Với tiêu chuẩn tuân thủ tôi có nghĩa là nó phải cung cấp các toán tử tăng dần và dereferencing thông thường, nhưng cũng có tất cả các số value_type, reference_type, ... typedefs, mà lần lượt được sử dụng bởi cấu trúc foreach để xác định loại cơ bản của các phần tử thùng chứa. Nhưng bạn có thể chuyển tiếp chúng từ std::vector<Type>::iterator.

+3

Nếu bạn thiếu các hàm thành viên 'begin' và' end' thì foreach cũng có thể sử dụng các hàm không phải là thành viên 'begin' và' end'. –

+0

@Mike Bạn có nghĩa là các chức năng miễn phí lấy container như một tham số duy nhất? Đẹp, tôi không biết điều đó. Hữu ích cho việc mở rộng các lớp container hiện có, tôi đoán vậy. –

6

Như những người khác đã nói, container của bạn phải thực hiện begin()end() chức năng (hoặc có chức năng toàn cầu hoặc std:: rằng lấy trường hợp của container của bạn như thông số).

Các chức năng đó phải trả về cùng một loại (thường là container::iterator, nhưng đó chỉ là một quy ước). Loại trả lại phải triển khai operator*, operator++operator!=.

Các vấn đề liên quan