У меня есть std::map<int, std::pair<short, float> >
, и мне нужно найти минимальный short
на этой карте. Как я могу использовать boost::bind
с std::min_element()
?Как использовать Boost.Bind для сложных типов?
boost::lambda
?
У меня есть std::map<int, std::pair<short, float> >
, и мне нужно найти минимальный short
на этой карте. Как я могу использовать boost::bind
с std::min_element()
?Как использовать Boost.Bind для сложных типов?
boost::lambda
?
map
итератор даст вам pair
где first
является int
ключом и second
является pair
значения для этой карты, так что если вы ч ad iterator it
, вы хотите, чтобы минимум всех значений it->second.first
. Функция min_element
ожидает функцию сравнения для своего третьего аргумента, поэтому вам нужно построить функцию сравнения, которая реализует second.first
из двух своих аргументов.
Мы начнем с некоторыми определениями типов, чтобы сделать код более читаемым:
typedef std::pair<short, float> val_type;
typedef std::map<int, val_type> map_type;
map_type m;
Мы будем использовать Boost.Lambda для своих перегруженных операторов, что позволяет нам использовать operator<
. Boost.Bind может связывать переменные-члены, а также функции-члены, поэтому мы также воспользуемся этим.
#include <boost/bind.hpp>
#include <boost/lambda/lambda.hpp>
using boost::bind;
// Comparison is (_1.second.first < _2.second.first)
std::cout <<
std::min_element(m.begin(), m.end(),
bind(&val_type::first, bind(&map_type::iterator::value_type::second, _1))
<
bind(&val_type::first, bind(&map_type::iterator::value_type::second, _2))
)->second.first;
Это также будет работать с boost::lambda::bind
.
bind
не может сделать это сам по себе, потому что first
и second
подвергаются как поля, а не методы (так что вы не можете уйти с чем-то вроде mem_fun
).
Вы можете сделать это, используя свой собственный функтор, конечно, хотя:
template <typename F, typename S>
struct select_first : std::binary_function<std::pair<F, S>&, F&>
{
F& operator()(std::pair<F, S>& toConvert)
{
return toConvert.first;
}
};
min_element(map.begin(), map.end(),
compose2(less<short>(),
compose1(select1st<pair<short, float> >(),
select2nd<map<int, pair<short, float>
>::value_type>()),
compose1(select1st<pair<short, float> >(),
select2nd<map<int, pair<short, float>
>::value_type>()))
).second.first;
(Конечно, кто-то собирается жаловаться, что это злоупотребление STL и что эти расширения не в C++ стандарт ...)
Ну, я бы жаловался на нестандартные расширения, но, насколько «STL-злоупотребление», я думаю, что это прекрасно :) +1. К счастью, нестандартные биты легко писать сами. –
Также известен как 'select1st' в некоторых библиотеках C++. – ephemient
@ephemient: True - не знал, что он уже включен в STL SGI. В этом случае я бы рекомендовал оставить это имя таким образом, потому что SGI поддерживает любой пара-подобный интерфейс, в то время как этот работает только с std :: pair. –