Итератор разыменования как часть составной цепочки boost :: bind

Я пытаюсь использовать связывание для создания функции, которая:

  • Получает карту м
  • возвращает m.begin () -> сначала

Для этого я пытаюсь использовать boost :: bind:

typedef map<int,int>::const_iterator (map<int,int>::*const_begin_end) () const;
bind(&pair<const int,int>::first, bind(static_cast<const_begin_end>(&map<int, int>::begin), _1));

Это не работает, потому что результат начала должен быть разыменован. Я думал что-то вроде

bind(&pair<const int,int>::first, bind(&operator*, bind(static_cast<const_begin_end>(&map<int, int>::begin), _1)));

Но это не сработает, так как нет глобального оператора *.

Вопросы:

  • Можно ли добиться этого, используя сложные цепочки boost :: bind? Как?
  • Более легко читаемые альтернативы?

0

Решение

я очень рекомендую Boost.Phoenix, это моя библиотека, когда речь заходит о написании функторов на лету в C ++ 03. Это превосходная альтернатива Boost.Bind — эта библиотека показывает свой возраст.

Например, Phoenix позволил нам использовать операторы на своих функторах для представления фактического использования этого оператора при вызове функтора. таким образом arg1 + arg2 является функтором, который возвращает сумму своих первых двух операндов. Это сильно сокращает bind шум. Первая попытка может выглядеть так:

bind(&pair<const int, int>::first
, *bind(static_cast<const_begin_end>(&map<int, int>::begin), arg1)) )

(LWS демо)

Но другой сильной стороной Phoenix является то, что он поставляется с некоторыми батареями. В нашем случае мы очень заинтересованы в <boost/phoenix/stl/container.hpp> потому что это включает в себя некоторую ленивую версию знакомых операций контейнеров, в том числе begin, Это очень удобно в нашем случае:

// We don't need to disambiguate which begin member we want anymore!
bind(&pair<const int, int>::first, *begin(arg1))

(LWS демо)


В заключение добавлю, что выражения связывания в C ++ 11 определены так, что указатели на элементы работают над что-нибудь который использует operator*, Так что из коробки вы можете сделать:

bind(&pair<const int, int>::first, bind(static_cast<begin_type>(&std::map<int, int>::begin), _1))

(LWS демо)

1

Другие решения

Вы можете вызывать связывание с указателями на функции-члены, а операторы-члены — это не что иное, как функции-члены:

 const_begin_end pBegin = &map<int,int>::begin;
x = bind(&std::pair::first,
bind(&std::map<int, int>::const_iterator::operator*,
bind(pBegin, _1)
);

А если серьезно, вы также можете просто написать правильную функцию, которая делает то, что вам нужно, вместо этого нечитаемого беспорядка boost.bind (вы можете сказать «ремонтопригодность»?).

Итак, для C ++ 03 функция:

template <class Map>
typename Map::key_type keyBegin(Map const& m)
{
return m.begin().first;
}

или функтор C ++ 03 (вы можете определить его локально внутри своей функции)

struct KeyBegin
{
typedef std::map<int, int> IntMap;
int operator()(IntMap const& m) {
return m.begin().first;
}
};

или лямбда на C ++ 11 (более читабельная, чем оргия связывания):

auto keyBegin = [](std::map<int, int> const& m) -> int {
return std::begin(m).first;
};
1