【问题标题】:Whats the cleanest way to compare to the result of a member function call与成员函数调用的结果进行比较的最干净的方法是什么
【发布时间】:2012-05-26 17:02:52
【问题描述】:

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

我经常发现自己为如下类的成员函数创建仿函数,然后用于 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 中的 lambda,但由于交叉编译器的限制,我无法切换到新标准。

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

难道没有更简单的方法使用标准 STL 或 boost 以更通用的方式编写此类函子或使用 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;
    };

【问题讨论】:

    标签: generics boost stl functor


    【解决方案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));
    

    【讨论】:

      【解决方案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;
      };
      

      【讨论】:

      • 再次感谢您的宝贵建议。这正是我想要的。为什么这样的东西不是某些库的一部分,看起来很方便。
      【解决方案3】:

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

      使用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 ) ) );
      }
      

      【讨论】:

        猜你喜欢
        • 2017-02-20
        • 2015-09-22
        • 1970-01-01
        • 1970-01-01
        • 2011-12-02
        • 2012-06-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多