PaulH
PaulH

Reputation: 7863

Using the iterator from one map as the key-type to another

I have a Visual Studio 2008 C++03 application where I would like to create a std::map that uses the iterator from another std::map as its key-type. But, I run in to a problem when I try to erase an element from that map using its key-type.

In this example, when an element in MyList gets to be more than 5 minutes old, a timer should fire and removes it from the map and destroy its age-timer.

typedef std::map< Foo, FooBar > MyList;
typedef std::map< MyList::iterator, boost::shared_ptr< Timer > > MyListAgeTimers;

class A
{
public:

    void AddItem( Foo& f, FooBar& fb )
    {
        CriticalSection::Guard g( lock_ );
        std::pair< MyList::iterator, bool > new_foo = 
            my_list_.insert( std::make_pair( f, fb ) );
        if( new_foo.second )
        {
            timers_.insert( std::make_pair( 
                new_foo.first, 
                boost::make_shared< Timer >( FiveMinutes, boost::bind( &A::OnAgeTimer, this, new_foo.first ) ) ) );
        }
    };

    void OnAgeTimer( MyList::iterator item )
    {
        CriticalSection::Guard g( lock_ );

        // erase by key-type generates an error:
        // functional(143) : error C2676: binary '<' : 'const std::_Tree<_Traits>::iterator' does not define this operator or a conversion to a type acceptable to the predefined operator
        timers_.erase( item );

        // erase by iterator. works okay.
        my_list_.erase( item );
    };

private:
    MyList my_list_;
    MyListAgeTimers timers_;
    CriticalSection lock_;
};

Can you not use the iterator from one map as the key-type to another? Or, do I need to define a specialized operator< for this?

EDIT:

The obvious thing to do (to me) is just this:

namespace std {
inline bool operator <( const MyList::iterator& a, const MyList::iterator& b )
{
    return a->first < b->first;
}
};

But, if that's correct, why is that not the default behavior for the std::operator< when comparing two iterators?

Upvotes: 1

Views: 360

Answers (1)

Pete Becker
Pete Becker

Reputation: 76428

std::map<key, value> requires that key have an operator<; that's what the map object uses to find a matching key. std::map<x, y>::iterator is a bidirectional iterator; it does not have an operator<, so you can't use it as the key type in another map unless you provide your own operator< or a function object to compare two iterators and decide which one comes before the other.

Upvotes: 6

Related Questions