Adapting STL Algorithms to Associative Containers (std::pair Elements)

Started by
7 comments, last by Enigma 16 years, 3 months ago
Is there a clean way to adapt the standard STL algorithms to std::pair elements? I'm frustrated with not being able to use common algorithms with associative containers like std::map. For example, let's say I have a map of some class A with a method I want to call on each.
class A // Just some class.
{
    void foo() {} // Member function I want to call with std::for_each().
};
std::map<int, A> con;
//...
std::for_each(con.begin(), con.end(), std::mem_fun_ref(A::foo)); // Won't work! The container contains std::pair<int, A> elements, not A elements!
So, is there a way around this problem? Obviously, std::for_each() isn't the only algorithm that doesn't work well with associative containers. Some offer member function versions, but the selection there is extremely limited. Thanks!
Advertisement
One way:
typedef std::map<int, A> MyMap;void do_foo(MyMap::value_type & vt) {  vt.second.foo();}std::for_each(con.begin(), con.end(), &do_foo);
Most(if not all) of the algorithms take a function as a last parameter so that you can access elements no matter how they are stored.(That way you can store pointers in a container and still find it useful)
as in:
int equator(pair<int,a> first, pair<int,a> second)
{
return first.fst == second.fst
}
find(vector.begin,vector.end,equator);

(I just made that up off the top of my head so it more than likely won't compile.)
or you can use boost.bind

std::for_each(  con.begin(), con.end(),    boost::bind(&A::foo, boost::bind(      &std::map<int, A>::value_type::second, _1)));


if you think programming is like sex, you probably haven't done much of either.-------------- - capn_midnight
Ah, thanks, ChaosEngine! That's exactly what I was just trying to do but I didn't get the syntax right!

Also, thanks for the function-based examples; I tend to forget that the algorithms usually just take functors or function pointers, so you can pretty much do anything you need.
I am sure I saw a "select2nd" functor once which did this job, and was a massive amount cleaner than that grotesque boost::bind monstrosity, but I can't find it.
SGI STL contains select1nd and select2nd as a non-standard extension. They shouldn't be too hard to implement manually:

template <typename Pair>struct select1st : std::unary_function<typename Pair::first_type, Pair>{    result_type& operator ()(Pair& pair)    {       return pair.first;    }    const result_type& operator ()(const Pair& pair)    {       return pair.first;    }}template <typename Pair>struct select2nd : std::unary_function<typename Pair::second_type, Pair>{    result_type& operator ()(Pair& pair)    {       return pair.second;    }    const result_type& operator ()(const Pair& pair)    {       return pair.second;    }}


It shouldn't be too difficult to generalize that for arbitrary boost/tr1/std::tuples, either.

You'd think that since there's already a special case for 2-tuples (ie. pairs), that they'd have standardised such functors to extract those values too. Ah well. Thanks for the implementation. :)
TR1 does specify the template free function get_element, which gets an indexed element from a tuple and is also specialised to get an element from a std::pair, i.e. get_element< 0 >(pair);

Σnigma

This topic is closed to new replies.

Advertisement