std::for_eachマニアック

STLではおなじみのfor_eachです。引数に最初と最後のイテレータもしくはポインタ、および処理する関数ポインタもしくは関数オブジェクトを入れることで完成。例えば、配列要素全てをインクリメントするには・・・

void Inc( int& d ){ ++d; }

int a[] = { 0,1,2,3,4,5,6,7,8,9 };
std::for_each( a, a + sizeof(a)/sizeof(int), Inc );

まあどの教科書にも載ってますが(^^; しかし使い道がイマイチ分からない私は実は今まで使ったことがないorz なのでいい機会なので使ってみようと思います(謎)

とりあえず、関数ポインタだけでなく関数オブジェクトも使えるので先ほどのをちょっと書き換え。

struct Inc{
	template< class I >	void operator()( I& i )const{ ++i; }
};

int a[] = { 0,1,2,3,4,5,6,7,8,9 };
std::for_each( a, a + sizeof(a)/sizeof(int), Inc() );

テンプレートになっているのは私の趣味ということで(ぇ これならint型以外も大丈夫。尤も、++が定義されていればの話だが・・・。

関数ポインタだけでなく関数オブジェクトも取れるということは非常に幅を広げています。なんでかというとstateを持つことが出来るからです。だから例えばこんなことも出来るんです。

template< class I >
struct Sum{
	Sum( I& i ):m_sum( i ){ m_sum = 0; }
	void operator()( const I& i ){ m_sum += i; }
	I& m_sum;
};

int a[] = { 0,1,2,3,4,5,6,7,8,9 };
int iSum;
std::for_each( a, a + sizeof(a)/sizeof(int), Sum< int >( iSum ) );
std::cout << iSum << std::endl;

配列の中身を全て足し合わせてその結果を得るプログラムです。関数ポインタだと無理ですね。せいぜいstatic変数を用いる程度だろうけど、それだと2回目以降が上手く行かない。

もうちょっと重い処理をやってみます。

template< class I >
class Average{
	I m_Sum;
	int m_iCount;
public:
	Average( const Average& ave ):m_Sum(ave.m_Sum), m_iCount(ave.m_iCount){}
	Average& operator=( const Average& ave ){ m_Sum = ave.m_Sum; m_iCount = ave.m_iCount; return *this; }
	Average():m_Sum(0), m_iCount(0){}
	void operator()( const I& i ){ m_Sum += i; ++m_iCount; }
	I Get(){ return m_Sum / m_iCount; }
};

double a[] = { 0,1,2,3,4,5,6,7,8,9, };
Average< double > ave;
ave = std::for_each( a, a + sizeof(a)/sizeof(double), ave );
std::cout << ave.Get() << std::endl;

配列の中身の平均を求めるプログラムです。先ほどまで関数オブジェクトは構造体でしたが今度はクラスです。先ほどのは一時オブジェクトとして渡せたので構造体ですが今回は普通にインスタンス生成するのでクラスにしました。深い意味はありません。
これ書いて始めて知ったんだけど、for_eachの戻り値って、渡した関数オブジェクトなんだね・・・。こういう使い方を見越した仕様としか思えん。おそるべし。

調子こいてもいっちょ

template< class I >
class Variance{
	I m_Sum2, m_Sum;
	int m_iCount;
public:
	Variance( const Variance& var ):m_Sum2(var.m_Sum2),m_Sum(var.m_Sum),m_iCount(var.m_iCount){}
	Variance& operator=( const Variance& var ){ m_Sum2 = var.m_Sum2; m_Sum = var.m_Sum; m_iCount = var.m_iCount; return *this; }
	Variance():m_Sum2(0),m_Sum(0),m_iCount(0){}
	void operator()( const I& i ){ m_Sum2 += i*i; m_Sum += i; ++m_iCount; }
	I Get(){ return (m_Sum2 / m_iCount) - (m_Sum / m_iCount) * (m_Sum / m_iCount); }
	void Reset(){ m_Sum2 = 0; m_Sum = 0; m_iCount = 0; }
};

double a[] = { 0,1,2,3,4,5,6,7,8,9, };
Variance< double > var;
var= std::for_each( a, a + sizeof(a)/sizeof(double), var);
std::cout << var.Get() << std::endl;

配列の中身の分散を求めるプログラムです。分散は二乗平均から平均の二乗を引けば出てきます。まあ詳しくは説明しません。とりあえずちょっとやりすぎた感が強いですね。ていうか、一行に詰め込みすぎorz


だんだん飽きてきたので最後に下らんネタプログラムを。

std::for_each( a, a + sizeof(a)/sizeof(double), std::bind1st( std::mem_fun1< std::ostream&, std::ostream, double >( &(std::ostream::operator<<) ), &std::cout ) );

配列の中身を全て表示するプログラムです。
こんなことせんでも普通にfor文回せばいいだけです。

for( double* p = a; p != a + sizeof(a)/sizeof(double); ++p ){
	std::cout << *p;
}

でまあ、いろいろやってみたけどやっぱり使い道が分かりませんでしたorz