2013-04-10 2 views
0

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

  • получает карту, м
  • возвращается m.begin() -> первый

для этого я пытаюсь использовать подталкивание :: обязывать:

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)); 

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

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

Но это не сработало, так как глобальный оператор не существует *.

Вопросы:

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

ответ

1

Я настоятельно рекомендую 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 demo)

Но другой конек Феникс является то, что она поставляется с некоторыми батареями. В нашем случае нас очень интересует <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 demo)


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

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

(LWS demo)

+0

Спасибо, я должен прочитать об этой библиотеке. – ricab

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 mess (можно сказать, «ремонтопригодность»?).

Таким образом, для 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; 
}; 
+0

Может быть, я не объяснить себя правильно, но я хотел что-то, что работал не только на карте :: const_iterator, но и для любого итератор (включая указатели). Карта была всего лишь примером. – ricab

Смежные вопросы