やあみんな元気にしてるかな。同じクラスの、異なるインスタンスオブジェクトが二つあるとき、ある特定のメンバの値でもって両者を比較したい場合はよくあることだね。そんなときのためのmem_compを今日は紹介するぞ。以前も同じものを紹介したことがあったんだけど、あまりにも行過ぎたマクロ化を行った結果、何が書いてあるのか読み返すことができなくなったよ。なのでプリプロセッサの展開の力を借りて今回ここに再びメモしておくぞ。
今回はそういう次第なわけなんだが、新しいこともあってそれは、オブジェクトのポインタも引数として受け付けるというわけさ。
// mem_comp 基本 template< class T > class poc_ct{ public: typedef T param_type; }; template< class T > class poc_ct<T&>{ public: typedef T param_type; }; template< class S, class T, class Pred=less<typename poc_ct<S>::param_type> > class mem_comp_t{ public: explicit mem_comp_t( S T::*p , Pred pred=less<typename poc_ct<S>::param_type>()) :m_m( p ), m_pred( pred ) {} bool operator()( T& a, T& b)const{ return m_pred( a.*m_m, b.*m_m );} bool operator()( T* a, T* b )const{ return m_pred( a->*m_m, b->*m_m ); } S T::*m_m ; Pred m_pred; }; template< class S, class T, class Pred > mem_comp_t< S, T, Pred > mem_comp( S T::*p , const Pred& pred ) { return mem_comp_t< S, T, Pred >(p, pred); } template< class S, class T > mem_comp_t< S, T > mem_comp( S T::*p ) { return mem_comp_t< S, T >(p); }
使い方はもうみんなには必要ないと思うけど一応な。以下のような感じで使ってくれ。
int main( void ) { class A { public: A( int val ): _val( val ){} int _val; }; list< A* > la; { for( int i=0; i<10; ++i ) la.push_back( new A( 10*rand()/(float)RAND_MAX ) ); } vector< A > va; for each( A* ia in la ){ va.push_back( *ia ); }// ia for each( A* ia in la ){ cout << ia->_val << " "; }// ia cout << endl; { // ここだね。例えばこのように sort に渡せる mem_comp。 sort( va.begin(), va.end(), mem_comp( &A::_val ) );//★ la.sort( mem_comp( &A::_val ) );//★ } for each( A* ia in la ){ cout << ia->_val << " "; }// ia cout << endl; return 0; }
上記の実行結果はこうなるかな
0 5 1 8 5 4 3 8 8 7 0 1 3 4 5 5 7 8 8 8
どうだろう、こんな使い方だ。(sortに渡してるとこな)
オブジェクトのポインタのコンテナでも、実体のコンテナでもどちらでもいけるというわけさ。しかし、しかしだ。もし標準の何かを使えばこんなもの要らないよ、mem_compなんてなくたって簡単にメンバ比較できるよということがあればどうか是非教えてくれないか。
➡後日記:
それはC++0xのラムダ式だよ。C++0xのラムダ式は、boost::lambdaとは違って随分わかりやすい素直な記述ができるようになってるみたいだ。なのでこういうものはもう必要なくなるな