11

Is there a builtin function object that returns p->first and p->second, so that I can happily write

transform(m.begin(),m.end(),back_inserter(keys),get_first);
transform(m.begin(),m.end(),back_inserter(vals),get_second);

STL-based solution is the best, boost solution is second best.

Yeah, I know boost::lambda, I don't want to start using it.

Elazar Leibovich
  • 32,750
  • 33
  • 122
  • 169
  • 1
    It seems you've realised that no direct support exists in the STL (or presumably boost), why not write a simple function template to do this for you? it's bound to be clearer than either the `bind` approach or the non-standard approach... – Nim Mar 07 '11 at 09:51
  • 1
    @Nim, that's probably a good idea, however I'm always afraid that everyone on the team will come up with his own version of `littleTidbitMissingFromSpec`, so if I could find something solid on boost, it would be better. – Elazar Leibovich Mar 07 '11 at 16:53
  • a well documented utils (or aux) namespace is what you need! ;) – Nim Mar 07 '11 at 16:56

3 Answers3

9

There are nonstandard extensions to g++ and SGI called select1st and select2nd. So there's probably nothing in the STL for that.

Boost's bind can also do that, give it a pointer to the correct member function

boost::bind(&std::map<string,string>::value_type::second,_1)
Elazar Leibovich
  • 32,750
  • 33
  • 122
  • 169
5

We can easily write a select1st and select2nd:

struct select1st
{
   template< typename K, typename V >
   const K& operator()( std::pair<K,V> const& p ) const
   {
       return p.first;
   }
};

struct select2nd
{
   template< typename K, typename V >
   const V& operator()( std::pair<K,V> const& p ) const
   {
       return p.second;
   }
};

Here is an alternative, actually more flexible version:

struct select1st
{
   template< typename P >
   typename P::first_type const& operator()( P const& p ) const
   {
       return p.first;
   }
};

struct select2nd
{
   template< typename P >
   typename P::second_type const& operator()( P const& p ) const
   {
       return p.second;
   }
};

subsequently:

transform(m.begin(),m.end(),back_inserter(keys), select1st());
transform(m.begin(),m.end(),back_inserter(vals), select2nd());
CashCow
  • 30,981
  • 5
  • 61
  • 92
2

If you can use C++0x you can either use real lambdas since G++ 4.5 or you can use the new tuple-library which is fully compatible with std::pairs. Then you could use std::get<0> for first and std::get<1> for second.

If you are bound to C++98 you can use std::tr1::tuple instead of std::pair, as in TR1 get doesn't work with std::pair.

Also you can use bind from TR1 (tr1/functional) like Elazar described it.

filmor
  • 30,840
  • 6
  • 50
  • 48