にゃははー

はへらー

c++の演算子が変態

適当なクラスとか作ってSTLアルゴリズムとかの為にoperator<をオーバーロードすることって多いと思うけど、1つのクラスに対していくつかの比較関数を定義したいときにどうするか問題が出てくる。
そこで気がついたんだけど、使用するときに任意のメンバを比較出来るようにしたら最強だと思う。そこでメンバポインタ演算子を駆使してこんな関数オブジェクトを作ってみた。

#include <functional>

template < typename class_t, typename field_t, field_t class_t::*_field, typename comp_t = std::less< field_t > >
  class subpredicate
  : public std::binary_function< class_t, class_t, bool >
{
protected:
    comp_t _fn;

public:
    subpredicate( const comp_t &fn = comp_t() )
      : _fn( fn )
    {}

    inline bool operator()( const class_t &_To, const class_t &_Tp ) const
    { return this->_fn( _To.*_field, _Tp.*_field ); }
};

普段見慣れない演算子があったりしてキモイけど意外とホイホイ動いてくれる。

#include <list>
#include <algorithm>
#include <iostream>

struct Int
{
    int i;
    Int( int _ )
      : i( _ )
    {}
};

int main( void )
{
    std::list< Int > hoge = { 0, 1, 2, 3, 4, 5, 6, 7 };
    for ( std::list< Int >::iterator itr = hoge.begin();
          itr != hoge.end(); ++itr )
    { std::cout << itr->i << " " << std::ends; }
    std::cout << std::endl;

    hogee.remove_if( std::bind2nd( subpredicate< Int, int, &Int::i >(), 4 ) );

    for ( std::list< Int >::iterator itr = hoge.begin();
          itr != hoge.end(); ++itr )
    { std::cout << itr->i << " " << std::ends; }
    std::cout << std::endl;

    return 0;
}

Intなんてふざけたクラスを使ってみるとこんな感じ。
実行するとちゃんと4より小さい要素が削除されてます。

再帰的に適用もできて

struct Int
{
    struct imp
    {
        int _;
        imp( int i )
          : _( i )
        {}
    } _;

    Int( int i )
      : _( i )
    {}
};

という頭の悪い構造体があったら

hoge.remove_if( bind2nd( subpredicate< Int, Int::imp, &Int::_, subpredicate< Int::imp, int, &Int::imp::_ > >(), 4 ) );

とすると同様の効果が得られます。なげぇ...

今までの場合は構造体と構造体の比較ですが、構造体と任意の型の比較はまた別のファンクタを作らなければなりません。(STLのbind系が型を参照してくるので)

2010/05/10 追記
テンプレートをもっと活用してより使いやすく