2010-05-16 20 views
13

Piszę własną klasę kontenerów i napotkałem problem, którego nie mogę zrozumieć. Oto próbka bare-bone, która pokazuje problem.Problem iteratora i const_iteratora C++ dla własnej klasy kontenera

Składa się z klasy kontenera i dwóch klas testowych: jednej klasy testowej używającej std: wektor, który ładnie kompiluje i drugiej klasy testowej, która stara się używać mojej własnej klasy kontenerów w dokładnie taki sam sposób, ale nie udaje się skompromitować.

#include <vector> 
#include <algorithm> 
#include <iterator> 

using namespace std; 

template <typename T> 
class MyContainer 
{ 
public: 

    class iterator 
    { 
    public: 
    typedef iterator self_type; 
    inline iterator() { } 
    }; 

    class const_iterator 
    { 
    public: 
    typedef const_iterator self_type; 
    inline const_iterator() { } 
    }; 

    iterator begin() { 
    return iterator(); 
    } 

    const_iterator begin() const { 
    return const_iterator(); 
    } 
}; 

// This one compiles ok, using std::vector 
class TestClassVector 
{ 
public: 
    void test() { 
    vector<int>::const_iterator I=myc.begin(); 
    } 

private: 
    vector<int> myc; 
}; 

// this one fails to compile. Why? 
class TestClassMyContainer 
{ 
public: 
    void test(){ 
    MyContainer<int>::const_iterator I=myc.begin(); 
    } 

private: 
    MyContainer<int> myc; 
}; 


int main(int argc, char ** argv) 
{ 
    return 0; 
} 

gcc mówi mi:

test2.C: In member function ‘void TestClassMyContainer::test()’:

test2.C:51: error: conversion from ‘MyContainer::iterator’ to non-scalar type ‘MyContainer::const_iterator’ requested

nie jestem pewien, gdzie i dlaczego kompilator chce przekształcić iterator do const_iterator dla własnej klasy, ale nie dla klasy STL wektora. Co ja robię źle?

Odpowiedz

9

Po wywołaniu begin() kompilator domyślnie tworzy wywołanie niestanowiące stałej begin(). Ponieważ myc nie jest const, nie ma możliwości poznania, że ​​zamierzasz użyć stałej begin(), a nie stałej begin().

Iterator STL zawiera operator obsadowy, który pozwala na konwersję cichą iterator na const_iterator. Jeśli chcesz, to do pracy trzeba dodać jedną, jak również tak:

class iterator 
{ 
public: 
    typedef iterator self_type; 
    inline iterator() { } 

    operator const_iterator() { return const_iterator(); } 
}; 

lub zezwolić const_iterator być zbudowany z iterator tak:

class const_iterator 
{ 
public: 
    typedef const_iterator self_type; 

    const_iterator(iterator&) {} 
    inline const_iterator() { } 
}; 
+0

Wielkie dzięki. Teraz wystarczy sprawdzić, czy deklaruję const_iterator jako przyjaciela iteratora ... lub piszę funkcje akcesor do prywatnych iteratorów, ale to powinno być wykonalne. – BaCh

3

W pojemnikach iterator typ musi być wymienny na const_iterator. Jest to potrzebne w przypadkach, w których wykonuje się iterację poprzez zmienny kontener przy użyciu niemodalnego (const) iteratora, ponieważ ma to sens. W twoim przypadku myc jest zmienny (nie stały), ale tworzysz na nim iterator const.

+1

Jest odwrotnie - 'iterator' musi być konwertowalny na' const_iterator' – sbk

+0

Dobra, pomieszałem to. – doublep

2

powinien mieć wygląd Boost Biblioteka iteratorów, w szczególności sekcje iterator_facade i iterator_adaptor. Zawierają nagromadzenie iteratora "od zera".

Pokaże ci, jak pisać iteratory bez zbytniego powielania, ponieważ większość razy kod wersji const i non const jest prawie taki sam, z wyjątkiem samej kwalifikacji const. Używając szablonów, można go raz napisać, a następnie zadeklarować dwa różne typy i to ilustruje dokumentacja biblioteki.

Powiązane problemy