C ++ 03 Поиск элемента на основе значения функции-члена - PullRequest
0 голосов
/ 08 ноября 2018

Я пытаюсь найти элемент в std :: vector, основанный на функции-члене, но, к сожалению, у меня нет доступа к полному C ++ 11-совместимому компилятору.

Я знаю, что могу использовать функтор для решения этой проблемы, но мне интересно, есть ли "функциональный" способ для достижения того же результата.

Ниже приведен фрагмент, который описывает мою проблему:

#include <iostream>
#include <string>
#include <functional>
#include <algorithm>
#include <vector>

struct Class {
  int type_;

  Class(int type): type_(type) {
  }

  int GetType() {
    return type_;
  }
};

struct Functor {
  Functor(int t): t_(t) {
  }

  bool operator()(Class c) {
    return c.GetType() == t_;
  }

  int t_;
};

int main() {    
  // It also works
  std::vector<Class> v2 { Class(1), Class(2), Class(3), Class(4), Class(5) };
  auto it2 = std::find_if(v2.begin(), v2.end(), Functor(4));
  std::cout << (it2 != v2.end() ? "Found!" : "Not found!") << std::endl;

  // It would solve, but I can't use due to compiler limitations :(
  it2 = std::find_if(v2.begin(), v2.end(), [](auto& v) { return v.GetType() == 4; });
  std::cout << (it2 != v2.end() ? "Found!" : "Not found!") << std::endl;

  // Is there any "functional based" solution to this, using std::mem_fun, std::bind1st, etc.?
  // it2 = std::find_if(v2.begin(), v2.end(), ???);

  return 0;
}

если бы мой std :: vector был сформирован не сложным типом, я бы сделал что-то вроде:

  std::vector<int> v1 { 1, 2, 3, 4, 5 };
  auto it1 = std::find_if(v1.begin(), v1.end(), std::bind1st(std::equal_to<int>(), 4));
  std::cout << (it1 != v1.end() ? "Found!" : "Not found!") << std::endl;

Есть ли какое-либо решение написать код, подобный приведенному выше?

Изменить:

Я использую GCC 4.4.1

Edit2:

Основываясь на некоторых комментариях и ответе @ scohe001, я решил бы проблему с перегрузкой глобального оператора ==.

Но мое любопытство еще не удовлетворено :) Нет ли способа достичь моей цели с помощью набора инструментов std <funtional>?

Edit3:

Только для пояснения: после прочтения ответов и комментариев я знаю, что можно решить простой пример, который я разместил, перед использованием перегрузки operator==(int), а также знаю, что я могу использовать function object (functor) для того же работа лямбда-выражения. Но мой настоящий вопрос: используя ТОЛЬКО набор инструментов, доступный в <functional> (std :: mem_fun, std :: bind1st, std :: equal_to и т. Д.), Могу ли я "имитировать" поведение лямбда / функтора? Если да, то как я могу «связать» вызовы функции, чтобы сделать это?

Edit4:

Очевидно, что нет способа решить мою проблему ТОЛЬКО с использованием существующего набора инструментов из <functional>, поэтому я принимаю ответ @Caleth, как только он приблизится к тому, что я пытался сделать.

Ответы [ 3 ]

0 голосов
/ 08 ноября 2018

Я бы реализовал функции, которые вам нужны из более поздних стандартов, в своих собственных пространствах имен, если позволяет язык. Таким образом, вам не нужно вносить необоснованные / запутанные / неоптимальные изменения в программу, которые потом вам будет сложно определить и исправить, когда / если вы обновитесь до более поздней версии C ++. Изменить все cpp11:: на std:: будет легко по сравнению.

namespace cpp11 {
    // copy find_if from cppreference and adapt it for C++03
}
0 голосов
/ 09 ноября 2018

Вы должны написать bind_both адаптер самостоятельно

it2 = std::find_if(v2.begin(), v2.end(), bind_both(std::equal_to<int>(), std::mem_fn_ref(&Class::getType), 4));

И у него будет комбинаторный взрыв возможностей

template <typename Binary, typename Left, typename Arg>
class bind_left_t : public std::unary_function<Arg, typename Binary::result_type> {
    Binary b;
    Left l;
    typename Binary::second_argument_type r;
public:
    bind_left_t(Binary b, Left l, typename Binary::second_argument_type r) : b(b), l(l), r(r) {}
    typename Binary::result_type operator()(      Arg & arg) const { return b(l(arg), r); }
    typename Binary::result_type operator()(const Arg & arg) const { return b(l(arg), r); }
};

template <typename Binary, typename Right, typename Arg>
class bind_right_t : public std::unary_function<Arg, typename Binary::result_type> {
    Binary b;
    typename Binary::first_argument_type l;
    Right r;
public:
    bind_right_t(Binary b, typename Binary::first_argument_type l, Right r) : b(b), l(l), r(r) {}
    typename Binary::result_type operator()(      Arg & arg) const { return b(l, r(arg)); }
    typename Binary::result_type operator()(const Arg & arg) const { return b(l, r(arg)); }
};

template <typename Binary, typename Left, typename Right, typename Arg1, typename Arg2>
class bind_both_t : public std::binary_function<Arg1, Arg2, typename Binary::result_type> {
    Binary b;
    Left l;
    Right r;
public:
    bind_both_t (Binary b, Left l, Right r) : b(b), l(l), r(r) {}
    typename Binary::result_type operator()(      Arg1 & arg1,       Arg2 & arg2) const { return b(l(arg1), r(arg2)); }
    typename Binary::result_type operator()(const Arg1 & arg1,       Arg2 & arg2) const { return b(l(arg1), r(arg2)); }
    typename Binary::result_type operator()(      Arg1 & arg1, const Arg2 & arg2) const { return b(l(arg1), r(arg2)); }
    typename Binary::result_type operator()(const Arg1 & arg1, const Arg2 & arg2) const { return b(l(arg1), r(arg2)); }
};

Дополнительные аргументы шаблона (Arg, Arg1 и Arg2) устранение неоднозначности между тремя формами при вызове bind_both

template <typename Binary, typename Left>
bind_left_t<Binary, Left, typename Left::argument_type> bind_both(Binary b, Left l, typename Binary::second_argument_type r)
{
    return bind_left_t<Binary, Left, typename Left::argument_type>(b, l, r);
}

template <typename Binary, typename Right>
bind_right_t<Binary, Right, typename Right::argument_type> bind_both(Binary b, typename Binary::first_argument_type l, Right r)
{
    return bind_right_t<Binary, Right, typename Right::argument_type>(b, l, r);
}

template <typename Binary, typename Left, typename Right>
bind_both_t<Binary, Left, Right, typename Left::argument_type, typename Right::argument_type> bind_both(Binary b, Left l, Right r)
{
    return bind_both_t<Binary, Left, Right, typename Left::argument_type, typename Right::argument_type>(b, l, r);
}
0 голосов
/ 08 ноября 2018

Похоже, вы не можете изменить само определение структуры, поэтому создайте перегрузку для operator== в глобальной области видимости:

bool operator==(const Class &lhs, const Class &rhs) {
    return lhs.type_ == rhs.type_;
}

Тогда вы можете использовать обычный старый find:

std::find(v2.begin(), v2.end(), Class(4));
...