C ++ 03根据成员函数值查找元素

时间:2018-11-08 17:20:12

标签: c++ c++03

我试图在基于成员函数的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

编辑2:

基于一些评论和@ scohe001的回复,我将解决重载全局==运算符的问题。

但是我的好奇心还没有满足:) 使用<funtional>中的std工具集无法实现我的目标吗?

Edit3:

仅需澄清:在阅读了答复和评论之后,我知道可以解决在使用operator==(int)重载之前发布的简单示例,并且知道我可以使用function object (functor)做与lambda表达式相同的工作。但是,我真正的问题是:仅使用<functional>中可用的工具集(std :: mem_fun,std :: bind1st,std :: equal_to等),我可以“模仿” lambda / functor的行为吗?如果是这样,我该如何“链接”功能调用来做到这一点?

编辑4:

显然,仅使用<functional>中的现有工具集就无法解决我的问题,因此,我接受@Caleth的答复,因为它是最接近我尝试的答复要做。

3 个答案:

答案 0 :(得分:1)

您必须自己编写一个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时,多余的模板参数(Arg1Arg2bind_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);
}

答案 1 :(得分:0)

听起来您无法修改结构定义本身,因此请在全局范围内为operator==创建一个重载:

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

然后您可以使用常规的旧find

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

答案 2 :(得分:0)

只要语言允许,我将在其自己的名称空间中实现更高标准所需要的功能。这样,您就无需对程序进行不必要的/复杂的/非最佳的更改,以后您将很难识别并更正何时/是否升级到更高版本的C ++。比较起来,将所有cpp11::更改为std::会很容易。

namespace cpp11 {
    // copy find_if from cppreference and adapt it for C++03
}