简体   繁体   中英

Customize an iterator for a wrapped list

I've got a class, memberlist, that contains a std::list of class memberinfo. These represents the peers on a network.

I use the class to add some functionality to the list.

I want to expose some iterators (begin and end) so that outside code can loop through my internal list and read their data. However, I want to have two ways of doing this - one that includes an element for the localhost, and one that doesn't.

What's a good way to do this?

I could put the local node first, then have like begin(showlocal=false) just give the second element instead of the first. Or someone suggested storing a pair of with the bool saying if it's local or not.

Any suggestions on a good way to do this? I'm not too great on advanced STL stuff yet.

Personally I would approach this in a different way and have your memberinfo have a way of telling you if it's local or not.

That way you're not specialising your collection class due to a specialisation of the contained objects. In fact you could just use a standard std::list<memberinfo> .

Eg

class memberinfo
{
    bool IsLocal( ) const;
}

Then you would choose whether you're interested in local members or not while you're iterating through the contained objects.

Eg

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

As I said in comment to your question, I think your first solution is reasonable. However, I'm not sure that giving a parameter to begin is the best approach for discriminating the two cases. The major problem with this is that you cannot use your full collection (including the localhost member) as a range, meaning that you cannot use Boost.Range algorithms or the C++11 range-based for loop.

A simple solution would be to have two different member functions returning the appropriate range, as a pair of iterators. Boost.Range provides a sub_range class , which seems rather appropriate (you want to return a sub-range of the list of members). Here is a sample code using this approach:

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

Now, you can use either all() or some() depending on whether you want to include local or not, and both can be used as ranges:

int main()
{
    MemberList ml;

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

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

And of course, you can still use iterators as usual:

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

If you don't want to leak the fact that your members are stored in a std::vector , you can use any_range , which erases the underlying iterator type.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM