2009-05-23 4 views
3

Ich brauche einen "Container", der sich wie folgt verhält. Es hat 2 Untercontainer, A und B genannt, und ich muss in der Lage sein, nur über A, nur B und A und B zu iterieren. Ich möchte keinen zusätzlichen Speicherplatz für redundante Daten verwenden, also habe ich mir überlegt, meinen eigenen Iterator zu verwenden, um über A und B kombiniert zu iterieren. Was ist der einfachste Weg, einen eigenen Iterator zu erstellen? Oder, was ist ein anderer Weg, dies zu tun?Machen Sie einen C++ - Iterator, der 2 Container durchquert

EDIT Letztendlich glaube ich nicht, dass es gutes Design war. Ich habe die gesamte Klassenhierarchie neu gestaltet. +1 für das Refactoring. Ich habe dieses Problem jedoch ausreichend gelöst. Hier ist eine abgekürzte Version von dem, was ich getan habe, als Referenz; Es verwendet boost :: filter_iterator. Sei T der Typ im Container.

enum Flag 
{ 
    A_flag, 
    B_flag 
}; 

class T_proxy 
{ 
public: 
    T_proxy(const T& t, Flag f) : t_(t), flag_(f) {} 
    operator T() const {return t_;} 
    Flag flag() const {return flag_;} 
    class Compare 
    { 
    public: 
     Compare(Flag f) : matchFlag_(f) {} 
     operator() (const T_proxy& tp) {return tp.flag() == matchFlag_;} 
    private: 
     Flag matchFlag_; 
    }; 
private: 
    T t_; 
    Flag flag_; 
}; 

class AB_list 
{ 
public: 
    typedef T_proxy::Compare Compare; 
    typedef vector<T_proxy>::iterator iterator; 
    typedef boost::filter_iterator<Compare, iterator> sub_iterator; 
    void insert(const T& val, Flag f) {data_.insert(T_proxy(val, f));} 
    // other methods... 

    // whole sequence 
    iterator begin() {return data_.begin();} 
    iterator end() {return data_.end();} 

    // just A 
    sub_iterator begin_A() {return sub_iterator(Compare(A_flag), begin(), end()); 
    sub_iterator end_A() {return sub_iterator(Compare(A_flag), end(), end()); 

    // just B is basically the same 
private: 
    vector<T_proxy> data_; 
}; 


// usage 
AB_list mylist; 
mylist.insert(T(), A_flag); 
for (AB_list::sub_iterator it = mylist.begin_A(); it != mylist.end_A(); ++it) 
{ 
    T temp = *it; // T_proxy is convertible to T 
    cout << temp; 
} 

Antwort

7

ist, werde ich meine Antwort auf eine ähnliche Frage umbuchen. Ich denke, das wird tun, was du willst.

Verwenden Sie eine Bibliothek wie Boost.MultiIndex zu tun, was Sie wollen. Es skaliert gut und es gibt viel weniger Kesselplattencode, wenn Sie neue Indizes hinzufügen möchten. Es ist auch in der Regel more space and time efficient

typedef multi_index_container< 
    Container, 
    indexed_by< 
    sequenced<>, //gives you a list like interface 
    ordered_unique<Container, std::string, &Container::a_value>, //gives you a lookup by name like map 
    ordered_unique<Container, std::string, &Container::b_value> //gives you a lookup by name like map 
    > 
> container; 

Wenn Sie über einen Index iterieren, Sie zu einem anderen Index unter Verwendung des Iterators Projektions Konzept in der Bibliothek wechseln.

+0

Boost.MultiIndex scheint jedoch keine Möglichkeit zu haben, Elemente auszuschließen. – rlbond

0

Haben einen Behälter, der den Wert speichert Sie in zusammen interessiert sind mit einem Kennzeichen, das anzeigt, ob es in A oder B.

0

Sie könnten auch einen einzelnen Container erstellen, der std :: pair <> Objekte enthält.

Billy3