Does anyone know if there's a de-facto standard (i.e., TR1 or Boost) C++ function object for accessing the elements of a std::pair?  Twice in the past 24 hours I've wished I had something like the keys function for Perl hashes.  For example, it would be nice to run std::transform on a std::map object and dump all the keys (or values) to another container.  I could certainly write such a function object but I'd prefer to reuse something that's had a lot of eyeballs on it.
- 3,262
 - 2
 - 34
 - 36
 
- 34,290
 - 15
 - 75
 - 125
 
6 Answers
boost::bind is what you look for.
boost::bind(&std::pair::second, _1); // returns the value of a pair
Example:
typedef std::map<std::string, int> map_type;
std::vector<int> values; // will contain all values
map_type map;
std::transform(map.begin(), 
               map.end(), 
               std::back_inserter(values), 
               boost::bind(&map_type::value_type::second, _1));
- 496,577
 - 130
 - 894
 - 1,212
 
From the way you worded your question, I'm not sure this is a proper response, but try boost::tie (part of the Boost::tuple library). It works on std::pairs too.
- 38,128
 - 22
 - 77
 - 87
 
boost::bind is often used to adapt std::map containers for use with algorithms. Here is an example:
void print_string(const std::string& s) {
  std::cout << s << '\n';
}
std::map<int,std::string> my_map;
my_map[0]="Boost";
my_map[1]="Bind";
std::for_each(my_map.begin(), my_map.end(),
              boost::bind(&print_string, boost::bind(
              &std::map<int,std::string>::value_type::second,_1)));
- 26,961
 - 9
 - 82
 - 99
 
What about using combinations of different containers.
For example when I wanted to partition a vector into items contained in a supplemental map and items that where not contained in the supplemental map I used the following:
typedef int DWORD; 
typedef std::pair<std::string, bool> user_info; 
typedef std::map<DWORD, user_info> USER_MAP; 
typedef std::vector<DWORD> VEC_STAFF; 
VEC_STAFF::iterator it = std::partition(Staff.begin(), Staff.end(), (bind(&USER_MAP::find, m_Users, _1) != m_Users.end()));
Now I have a second problem - during the running of the application the status bool of user_info can change, and later on I want to re-partition the vector with items that have a status bool of true rather than just being contained in the supplemental map.
However I seem to have a problem accessing the second item of a nested pair.
I tried the following but I cannot seem to access the nested pair!
CActiveUsers::VEC_STAFF::const_iterator itCurEnd = partition(Staff.begin(), Staff.end(), bind(&USER_MAP::value_type::second::second, bind(&USER_MAP::find, &m_Users, _1)) == true); 
- 1,045
 - 2
 - 12
 - 25
 
Take a look at boost::adaptors. There are predefined adaptors for iterating over map keys or values without copying them to an intermediate container.
- 2,229
 - 1
 - 25
 - 43
 
One option that wasn't suggested is std::tr1::get.  See sections 6.1.2 and 6.1.4 of n1745.
std::pair< std::string, int > p( "foo", 1729 );
int hr = std::tr1::get< 1 >( p );
Definitely not as easy to use as bind in the map extraction case you mentioned but still worth knowing about.  Adapting Johannes' code:
typedef std::map<std::string, int> map_type;
std::vector<int> values; // will contain all values
map_type map;
// std::tr1::get is overloaded so we need to help the compiler choose
const map_type::value_type::second_type & (*get)( const map_type::value_type & ) =
  &std::tr1::get< 1, map_type::value_type::first_type, map_type::value_type::second_type >;
std::transform(map.begin(), 
               map.end(), 
               std::back_inserter(values), 
               get);
- 3,771
 - 1
 - 19
 - 30