class Blah
{
public:
int i;
Blah() { i=0; }
void doI (bool yes) { if (yes) i++; }
void isI (void) const { }// { return i==0; }
bool getI (void) { return i!=0; }
};
void doSomething (void)
{
typedef std::map<U32, Blah> mapDef;
mapDef my_map;
// test 1 (compiler error)
for_each( my_map.begin(), my_map.end(),
compose1( mem_fun( &Blah::isI), select2nd<mapDef::value_type>()));
//remove_if( my_map.begin(), my_map.end(),
// compose1( mem_fun( &Blah::isI), select2nd<mapDef::value_type>()));
}
🔒 Locked
std::map and for_each
Advertisement
Original Post
Hi, I want to erase some elements of a map, depending on a member function returning true or false (for the example, I'm using for_each because it's a little bit easier). I tried the code below, but I'm getting the following error: ..\STLport-4.6.2\stlport\stl\_function.h(209): error C2664: 'void _STL::const_mem_fun_t<_Ret,_Tp>::operator ()(const _Tp *) const' : cannot convert parameter 1 from 'const _STL::pair<_T1,_T2>::second_type' to 'const Blah *' with [ _Ret=void, _Tp=Blah ] and [ _T1=const Orc::U32, _T2=Blah ] Note that it expects a pointer - instead of the actual element... Any ideas anyone what I'm doing wrong?
Quote:
Original post by gumpy macdrunken Quote:
Original post by Kitt3n
I want to erase some elements of a map, depending on a member
function returning true or false (for the example, I'm using for_each
because it's a little bit easier).
use remove_if instead of for_each.
He's not trying to implement remove_if in terms of for_each. He's trying to get for_each to work first, because it has a simpler interface, with the expectation that solving the problem there will answer the question.
And yes, you need to use mem_fun_ref instead of mem_fun. The former generates functors that accept elements-which-are-things-with-the-member-function-by-reference; the latter generates functors that accept elements-which-are-pointers-to-thing-with-the-member-function.
Right. Which makes sense, if you think about how the algorithm is implemented. Before removing the end elements, the invariants would be totally violated.
However, since map iterators are much more "stable" than those of, say, vectors, you can easily accomplish what you want by manually looping and erasing. A shame there doesn't seem to be an algorithm to handle it :(
However, since map iterators are much more "stable" than those of, say, vectors, you can easily accomplish what you want by manually looping and erasing. A shame there doesn't seem to be an algorithm to handle it :(
Quote:
Original post by SiCrane
Now for the bad news: you can't use remove_if() on an associative container. The copy over semantics of remove_if() won't compile because of the const-ness of the value_types.
Darn, that sucks...
>you can easily accomplish what you want by manually looping and erasing.
>A shame there doesn't seem to be an algorithm to handle it :(
Yeah, I know - but I was trying to remove all the manual loops
in my code and replace them by algorithms.
Well you can always take the loops and make your own functions for erasing map elements. Something like:
The iteration statements are a little strange due to the need to make sure that iterators always stay valid.
template <typename MapType>void map_remove_key(MapType & map, typename MapType::key_type key) { typedef typename MapType::iterator IterType; typedef typename MapType::key_type KeyType; for (IterType i = map.begin(); i != map.end(); /* nothing */) { if (i->first == key) map.erase(i++); // increment and erase old value else ++i; }}template <typename MapType, typename Predicate>void map_remove_if(MapType & map, Predicate pred) { typedef typename MapType::iterator IterType; for (IterType i = map.begin(); i != map.end(); /* nothing */) { if (pred(*i)) map.erase(i++); // increment and erase old value else ++i; }}The iteration statements are a little strange due to the need to make sure that iterators always stay valid.
@SiCrane
Great idea - this way the nasty iterator stuff is hidden away.
Calling the member function to determine if it should be erased
works perfectly now - thanks!
I do have one more question though,
I'm using the template like this:
map_remove_if( my_map,
compose1( mem_fun( &Blah::isI), select2nd<mapDef::value_type>()));
Now apparently compose will only call const-member functions, I would
however also like to call non-const member functions (because I need
to modify the element when it is (about to be) removed from the map)...
Any suggestions on that one?
Great idea - this way the nasty iterator stuff is hidden away.
Calling the member function to determine if it should be erased
works perfectly now - thanks!
I do have one more question though,
I'm using the template like this:
map_remove_if( my_map,
compose1( mem_fun( &Blah::isI), select2nd<mapDef::value_type>()));
Now apparently compose will only call const-member functions, I would
however also like to call non-const member functions (because I need
to modify the element when it is (about to be) removed from the map)...
Any suggestions on that one?
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement