0

これが以前に尋ねられたことがある場合は、申し訳ありませんが、適切な解決策を見つけることができません。

次のようなクラスのメンバー関数のファンクターを作成して、後で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 のラムダについては知っていますが、クロスコンパイラの制限により、新しい標準に切り替えることができません。

私が見つけた最も関連性の高い質問は、クラスメンバー関数の結果を伴う stl remove_if ですが、与えられた解決策は、比較のために追加のメンバー関数を追加することを意味します。これは醜いです。

標準の 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;
    };
4

3 に答える 3

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;
};
于 2012-05-19T10:36:41.527 に答える
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 ) ) );
}
于 2012-05-19T10:41:13.630 に答える
1
using namespace boost;
std::find_if(first, last, bind(std::equal<int>(), bind(&Foo::getId, _1), id));

これにより、ネストされたバインド式が作成され、 range 内の各要素に対してそれが呼び出されます[first,last)。ここで、要素に対してバインド式を呼び出すことは、Foo i次を呼び出すことと同じです。

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

つまり、i.getId()等しいかどうかをテストしますid

boost::bindC++ 11では、次のように置き換えることができますstd::bind

using namespace std::placeholders;
std::find_if(first, last, std::bind(std::equal<int>(), std::bind(&Foo::getId, _1), id));
于 2012-05-19T16:55:45.177 に答える