Как я могу найти значение на карте, используя только связующие - PullRequest
3 голосов
/ 13 ноября 2009

При поиске во втором значении карты я использую что-то вроде следующего:

typedef std::map<int, int> CMyList;
static CMyList myList;

template<class t> struct second_equal
{
    typename typedef t::mapped_type mapped_type;
    typename typedef t::value_type value_type;

    second_equal(mapped_type f) : v(f)   {};
    bool operator()(const value_type &a) { return a.second == v;};

    mapped_type v;
};
...    
int i = 7;
CMyList::iterator it = std::find_if(myList.begin(), myList.end(), 
                                    second_equal<CMyList>(i));

Вопрос: Как я могу сделать такую ​​находку в одной строке, не предоставляя самостоятельно написанный шаблон?

Ответы [ 4 ]

8 голосов
/ 13 ноября 2009

Используйте селектор, чтобы выбрать первый или второй элемент из value_type, который вы получаете с карты. Используйте связыватель, чтобы связать значение (i) с одним из аргументов функции std::equal_to. Используйте композитор, чтобы использовать выходные данные селектора в качестве другого аргумента функции equal_to.

//stl version
CMyList::iterator it = std::find_if(
    myList.begin(), 
    myList.end(), 
    std::compose1(
        std::bind2nd(equal_to<CMyList::mapped_type>(), i), 
        std::select2nd<CMyList::value_type>())) ;

//Boost.Lambda or Boost.Bind version
CMyList::iterator it = std::find_if(
    myList.begin(), 
    myList.end(), 
    bind( &CMyList::mapped_type::second, _1)==i);
0 голосов
/ 13 ноября 2009

Вы можете решить эту проблему, написать собственный алгоритм и использовать его вместо этого. Таким образом, вы не застряли в написании множества маленьких функторов.

template <typename Iter, typename T>
Iter find_second(Iter first, Iter last, T value) {
    while (first != last) {
        if (first->second == value) {
            return first;
        }
        ++first;
    }
    return first;
}

Примечание это не проверено и даже не скомпилировано.

Мне кажется, что решение этого с помощью связывателей просто требует много уродливого кода. То, что вы действительно просите, это новый алгоритм, так что просто добавьте алгоритм. С учетом вышесказанного, я бы, вероятно, в итоге реализовал что-то вроде Matthieu M. придумал.

0 голосов
/ 13 ноября 2009

Вы можете использовать Boost Lambda

CMyList::iterator it = std::find_if(
      myList.begin(), myList.end(), 
      boost::lambda::bind(&CMyList::value_type::second, boost::lambda::_1) == i);
0 голосов
/ 13 ноября 2009

Я собираюсь уйти добровольно. Проблема с лямбдами заключается в том, что (кроме C ++ 0x) вы не можете использовать что-то вроде _.second на данный момент.

Лично я, таким образом, использую:

template <class Second>
class CompareSecond
{
public:
  CompareSecond(Second const& t) : m_ref(t) {} // actual impl use Boost.callparams
  template <class First>
  bool operator()(std::pair<First,Second> const& p) const { return p.second == m_ref; }
private:
  Second const& m_ref;
};

С которыми я комбинирую:

template <class Second>
CompareSecond<Second> compare_second(Second const& t)
{
  return CompareSecond<Second>(t);
}

Для получения автоматического вычета типа.

И так я могу написать

CMyList::iterator it = std::find_if(myList.begin(), myList.end(), compare_second(i));

Правда, он не использует связующие.

Но, по крайней мере, мой читабелен и легко понятен, что, по моему мнению, превосходит всякую хитрость в хитрой хитрости

Примечание
на самом деле я пошел так далеко, что обернул алгоритмы STL, чтобы получить полные контейнеры, так что это было бы:

 CMyList::iterator it = toolbox::find_if(myList, compare_second(i));

, который (imho) явно читабелен, как вы можете получить без ключевого слова auto для вывода типа.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...