2012-09-14 73 views
1

我有一個類memberlist,其中包含類memberinfo的std::list。這些代表網絡上的對等體。自定義包裝列表的迭代器

我使用該類將一些功能添加到列表中。

我想公開一些迭代器(開始和結束),以便外部代碼可以遍歷我的內部列表並讀取它們的數據。但是,我想要有兩種方法來實現這一點 - 一種包含localhost元素,另一種不包含。

這樣做的好方法是什麼?

我可以先把本地節點,然後像begin(showlocal=false)只給第二個元素,而不是第一個。或者有人建議在bool中存放一對,說明它是否是本地的。

任何建議一個很好的方法來做到這一點?我對先進的STL還沒有太大的瞭解。

+1

你的第一個解決方案似乎很合適(在一種情況下將迭代器返回到第一個元素,在另一個情況下返回到第二個元素)。它可能不是最明確的方法,但它具有簡單的優點。如果你這樣做,我認爲解釋發生了什麼的一些評論會受到歡迎(明確指出第一個元素將始終與本地主機相對應,並正確記錄'begin'成員函數)。 –

回答

4

就我個人而言,我會以不同的方式來解決這個問題,並讓你的memberinfo有辦法告訴你它是否是本地的。

這樣你就不會專門​​化你的集合類了,因爲包含對象的專門化。事實上,你可以使用標準的std::list<memberinfo>

E.g.

class memberinfo 
{ 
    bool IsLocal() const; 
} 

然後,您將選擇是否對本地成員感興趣,而不是在遍歷包含的對象時感興趣。

E.g.

std::list<memberinfo>::iterator it; 
std::list<memberinfo> list; 

for (it = list.begin() ; it != list.end() ; it++) 
{ 
    if (it->IsLocal()) 
    { 
     // blah blah blah 
    } 
    else 
    { 
     // dum dee dum dee 
    } 
} 
+0

如果我理解正確,OP想要對所有成員進行相同的處理,但有時會包含特定成員(對應於localhost),有時將其放在一邊。我不認爲你提出的解決方案確實適合於這個目的。而且,它在標準算法的基於迭代器的設計中不太適合:爲了在某些計算中包含或排除本地成員,您需要某種過濾迭代器來測試當前成員是否爲本地成員。 [...] –

+0

[...]請注意,這可以用[Boost.'filter_iterator']很好地完成(http://www.boost.org/doc/libs/1_51_0/libs/iterator/doc /filter_iterator.html)和lambdas(或'std :: bind'):'auto it = boost :: make_filter_iterator([](MemberInfo const&mi){return!mi.IsLocal();},list.begin() ,list.end());'。 –

+0

我想這可以歸結爲O.P.問題的解釋。我傾向於圍繞適用於手頭問題的軟件設計我的軟件,而不是適應基於xyz的設計原則。 – Nick

0

正如我在對您的問題發表評論時所說的,我認爲您的第一個解決方案是合理的。不過,我不確定給參數begin是區分這兩種情況的最佳方法。主要的問題是你不能使用你的完整集合(包括本地主機成員)作爲範圍,這意味着你不能使用Boost.Range algorithms或者C++ 11基於範圍的for循環。

一個簡單的解決方案是將兩個不同的成員函數作爲一對迭代器返回適當的範圍。 Boost.Range提供了一個sub_range class,這似乎相當合適(您想返回成員列表的子範圍)。下面是使用這種方法的樣本代碼:

#include <boost/range.hpp> 

#include <iostream> 
#include <string> 
#include <vector> 

struct MemberInfo 
{ 
    std::string name; 
}; 

class MemberList 
{ 
    public: 

    typedef std::vector<MemberInfo>::iterator iterator; 
    typedef std::vector<MemberInfo>::const_iterator const_iterator; 

    MemberList() 
     : members_{MemberInfo{"local"}, MemberInfo{"foo"}, MemberInfo{"bar"}} 
    {} 

    boost::sub_range<std::vector<MemberInfo>> all() // includes localhost 
    { 
     return boost::sub_range<std::vector<MemberInfo>>(
      members_.begin(), members_.end()); 
    } 

    boost::sub_range<std::vector<MemberInfo> const> all() const 
    { 
     return boost::sub_range<std::vector<MemberInfo> const>(
      members_.begin(), members_.end()); 
    } 

    boost::sub_range<std::vector<MemberInfo>> some() // excludes localhost 
    { 
     return boost::sub_range<std::vector<MemberInfo>>(
      ++members_.begin(), members_.end()); 
    } 

    boost::sub_range<std::vector<MemberInfo> const> some() const 
    { 
     return boost::sub_range<std::vector<MemberInfo> const>(
      ++members_.begin(), members_.end()); 
    } 

    private: 

    std::vector<MemberInfo> members_; 
}; 

現在,您可以使用all()some()取決於你是否要包括local與否,都可以作爲範圍:

int main() 
{ 
    MemberList ml; 

    for (MemberInfo mi : ml.all()) { std::cout << mi.name << '\n'; } 

    for (MemberInfo mi : ml.some()) { std::cout << mi.name << '\n'; } 
} 

當然,你仍然可以使用迭代器像往常一樣:

std::find_if(ml.all().begin(), ml.all().end(), ...); 

如果你不想泄露你的成員都存儲在事實一個std::vector,你可以使用any_range,這會擦除底層的迭代器類型。