перебор std :: map с использованием boost :: bind - PullRequest
2 голосов
/ 26 февраля 2012

Я сделал небольшой пример, чтобы понять, как boost::bind () работает с коллекциями. У меня есть класс с именем Data:

class Data
{
public:
    void print ();
    const std::string& get () const;
    std::string& get () ;
};

Я создал std::vector объектов данных, называемых сэмплами, и я могу использовать bind так же, как работает std::mem_fun_ref.

std::for_each (samples.begin (),samples.end (),std::mem_fun_ref (&Data::print));
std::for_each (samples.begin (),samples.end (),boost::bind (&Data::print,_1));

Основная идея заключается в том, что bind возвращает функциональный объект типа bind_t<RetType=void, ObjType=Data, ArgType=void>. Функция-член в качестве первого параметра позволяет компилятору выводить RetType, ObjType и ArgType. Заполнитель _1 соответствует объекту данных, который должен быть предоставлен алгоритмом.

Затем std::for_each вызывает функциональный объект «для каждого» элемента следующим образом:

for ( ; first!=last; ++first ) f(*first);

bind_t::operator(ObjType& obj) вызывается, и его определение должно быть примерно таким:

return (obj.*_method ());

Я создал класс Filter, который выполняет некоторую обработку элемента данных.

class Filter
{
    void filter (Data& data);
    ...
};

Если я хочу применить фильтр к элементам данных в векторе, я вызываю bind следующим образом:

std::for_each (samples.begin (),samples.end (),boost::bind (&Filter::filter,filter,_1));

for_each передает объект Data в bind_t::operator(). В этом случае объект функции уже имеет объект и просто нуждается в параметре, поэтому в этом случае заполнитель _1 ссылается на аргумент.

А вот и мой вопрос:

Как можно использовать bind, если мне приходится перебирать std::map, а не вектор?

(Извините за все объяснения, я просто хочу убедиться, что понимаю, как работает bind)

Ответы [ 2 ]

2 голосов
/ 27 февраля 2012
#include <boost/bind.hpp>
#include <algorithm>
int main()
{
  struct Sample
  {
    int i_;
    double d_;
  };
  typedef std::map<int, Sample> Samples;
  struct Filter
  {
    void filter(const Sample &s)
    {
    }
  };
  Filter filter;
  Samples samples;
  std::for_each(samples.begin(), samples.end(), boost::bind(&Filter::filter, filter, boost::bind(&Samples::value_type::second, _1))); 
}
0 голосов
/ 26 февраля 2012

Конечно, вы можете использовать bind() для итерации по std::map<...>. Однако обратите внимание, что элементы в std::map<K, V> имеют тип std::pair<K const, V>, то есть связанная функция должна быть кабелем доступа к объектам этого типа. Тем не менее, я не знаю, что один bind() может быть использован для преобразования этого аргумента в аргумент, который вам действительно интересен (то есть в V). Для этого вам, вероятно, понадобится вспомогательная функция, которая вызывается для выполнения преобразования. Если вы bind() эту функцию также bind() можете сделать подходящую композицию, то есть, я думаю, что-то вроде этого должно работать:

template <typename Result>
struct project2nd {
    typedef Result const& result_type;
    template <typename T>
    result_type operator()(std::pair<T, Result> const& arg) const {
        return arg.second;
    }
};
...
... bind(&Filter::filter, filter, bind(project2nd<Data>(), _1)) ...

Чтобы bind() работал с объектом funciton, кажется, ему нужна информация о связанных типах: результат оператора вызова функции не может быть выведен, но, по-видимому, необходим для внутреннего использования. Я предполагаю, что bind() достаточно умен, чтобы передавать ссылки. В противном случае тип должен быть изменен на Result. Кроме того, я не знаю, должен ли bind() также знать тип аргумента. Если это так, табличка класса project2nd должна будет принимать оба типа в качестве аргумента.

...