什么是最简洁的方法来比较成员函数调用的结果

时间:2012-05-19 10:04:55

标签: generics boost stl functor

请原谅我,如果之前有人问我,我只是找不到合适的解决方案。

我经常发现自己为类的成员函数创建仿函数,如下所示用于find_if或者remove_if之后

class by_id{
  public:
    by_id(int id):mId(id) {}

    template <class T>
    bool operator()(T const& rX) const { return rX.getId() == mId; }

    template <class T>
    bool operator()(T* const pX) const { return (*this)(*pX); }

  private:
    int mId;
};

虽然这很好用,但它包含了很多样板和方法来为每个我想用来比较的成员函数定义一个类。

我知道C ++ 11中的lambdas,但由于交叉编译器的限制,我无法切换到新标准。

我发现最接近的相关问题是stl remove_if with class member function result但是给定的解决方案意味着添加额外的成员函数进行比较,这很难看。

使用标准STL是否有更简单的方法,或者可能以更通用的方式增强编写这些仿函数,或者使用bind来完全跳过它们?

像通用仿函数那样的东西会做,但我缺乏编写它的技能。 只是为了弄清楚我的想法:

  template<typename FP,typename COMP>
  class by_id{
      public:
        by_id(COMP id):mId(id) {}

        template <class T>
        bool operator()(T const& rX) const { return rX.FP() == mId; } 
        //of course this does not work

        template <class T>
        bool operator()(T* const pX) const { return (*this)(*pX); }

      private:
        COMP mId;
    };

3 个答案:

答案 0 :(得分:2)

如果您提前知道T(在创建by_id个对象时,可以将其设为by_id的模板参数,并将指向成员函数的指针传递给构造函数有点像:

template<typename T, typename COMP>
class by_id
{
 public:
  typedef COMP (T::*MemFunc)();
  by_id(COMP id, MemFunc mf) : mId(id), mmf(mf) {}

  bool operator()(T const& rX) const { return rX.*mmf() == mId; }

 private:
  COMP mId;
  MemFunc mmf;
};

答案 1 :(得分:1)

您可以将成员函数指针传递给比较器,以指示要比较的值。

使用make_comparer函数避免在使用时指定类型参数(类似于std::make_pair

#include <iostream>
#include <vector>
#include <algorithm>

template<typename T, typename R>
class comparer
{
public:
    typedef R ( T::*accessor_type ) () const;
    typedef R value_type;
    comparer ( accessor_type accessor, value_type value ) :
        accessor_ ( accessor ), value_ ( value ) { }

    accessor_type accessor_;
    value_type value_;

    bool operator() ( T const& rX ) const {
        return ( rX.*accessor_ ) () == value_;
    }
    bool operator() ( const T* pX ) const {
        return ( *this ) ( *pX );
    }
};

template <typename T, typename R>
comparer<T, R> make_comparer ( R ( T::*accessor ) () const, R value )
{
    return comparer<T, R> ( accessor, value );
}

class Foo
{
public:
    explicit Foo ( int id, int rank ) : id_ ( id ), rank_ ( rank ) { }
private:
    int id_, rank_;

public:
    int id() const {
        return id_;
    }
    int rank() const {
        return rank_;
    }

};

std::vector<Foo> foos;
typedef std::vector<Foo>::const_iterator FooIT;

void print ( FooIT it )
{
    if ( it == foos.end() )
        std::cout << "no match" << std::endl;
    else
        std::cout << "matches id: " << it -> id () << " rank: " << it -> rank () << std::endl;
}

main()
{

    foos.push_back ( Foo ( 1, 3 ) );
    foos.push_back ( Foo ( 2, 2 ) );
    foos.push_back ( Foo ( 3, 1 ) );

    std::cout << "compare id == 2 ";
    print ( std::find_if ( foos.begin(), foos.end(), make_comparer ( &Foo::id, 2 ) ) );

    std::cout << "compare id == 3 ";
    print ( std::find_if ( foos.begin(), foos.end(), make_comparer ( &Foo::id, 3 ) ) );

    std::cout << "compare rank == 3 ";
    print ( std::find_if ( foos.begin(), foos.end(), make_comparer ( &Foo::rank, 3 ) ) );
}

答案 2 :(得分:1)

using namespace boost;
std::find_if(first, last, bind(std::equal<int>(), bind(&Foo::getId, _1), id));

这将创建一个嵌套的绑定表达式,并为[first,last)范围内的每个元素调用它,其中调用元素Foo i的绑定表达式等同于调用:

std::equal<int>()( i.getId(), id )

即。它会测试i.getId()是否等于id

在C ++ 11中,您可以将boost::bind替换为std::bind

using namespace std::placeholders;
std::find_if(first, last, std::bind(std::equal<int>(), std::bind(&Foo::getId, _1), id));