関数オブジェクトを受け取るアルゴリズム

上述の文脈の流れで、STLのforeachなど、動作の述語引数として、関数オブジェクト、関数ポインタともに受け取るような関数は、

template< class T > void DoSomething( T func )
{
  int a, b;
  char* buff;
..
  func();// Tは引数なしで呼び出せる「何か」でさえあればよい
  //func( a ); //あるいは Tはintを引数にして呼べる「何か」でも
  //func( buff ); //あるいは Tはchar* を引数にして呼べる「何か」でもよい
..
}

という形で書かれるわけなのであり、T型が持つべきポリシーインタフェイスは、DoSomethingの作者が、上記のfunc()呼び出しの行をどう書くかだけできまる。気楽なものだ。この意味で、DoSomethingはホストクラスであり、T funcはポリシーであると言える。
しかし、こういう書き方をしたDoSomething関数は、その述語引数に渡せるものの自由度という意味において、以下に述べるように非常に高い汎用性を有しているのである!つまりこの、Tが関数オブジェクトたり得るというところが大きいのである。

TakoというクラスのHoge(int)というメソッド関数が、上記ポリシーを満たしているとする。このとき、例えばDoSomethingの述語引数として、bind1st( mem_fun1( &Tako::Hoge ), tako ) などという表記を渡してみれば、takoというTakoクラスのオブジェクトに対し、Hoge(int)という関数をDosomethingの述語として渡すことができる。言ってみればtako.Hoge(a) が、DoSomething内部のfunc(a)呼び出しの時点で呼ばれるというわけだ。
このように、bind やmem_fun といった関数アダプタと併用することにより、関数名が何だろうがクラスメソッドだろうが、関数オブジェクトだろうが、その引数インタフェースさえポリシーに合っていれば、何でもDoSomethingの述語関数に指定できるという世界が実現されるのである。

上記の関数オブジェクトを受け取るアルゴリズムの実装は、あくまで静的なオブジェクト生成の話である。何故かって、テンプレートはコンパイル時に展開されるだけだから。一つのインスタンスの中でアルゴリズムを動的に切り替えて使いたい場合などは、関数ポインタを使うことは有効だが、この場合でも、関数オブジェクトを使用する価値がある。それはなぜか。関数ポインタの引数以外にも追加情報を渡したい場合などがある。関数ポインタでとんだ先の処理に、追加情報をどうやって渡すだろうか?そんな時のために、関数オブジェクトを使った実装をしておくと便利だ。なぜなら、関数オブジェクトは、オブジェクトなので、追加情報は、その中にメンバとして、格納しておけば、渡った先の処理で、その追加情報を参照することが可能となるためである。このようなアルゴリズム切り替えをやりたい場合は、テンプレートメンバ関数を用意するのが有効な場合もある。
以下に、述語として関数ポインタと関数オブジェクトどちらでも指定可能な最小限の関数テンプレートアルゴリズムである「Calc」の作成例、その述語の作成例、およびこれら述語を使った、Calcの利用方法というか呼び出し方について、簡単なサンプルコードを示すので、参考として欲しい。

#include <iostream>
using namespace std;

// ○関数テンプレート(述語Predを要求)
template< class Pred > int Calc( int a, int b, Pred pred ){ 
  return pred(a, b); 
};

// ●述語その1(ただの関数つまり関数ポインタ)
int Plus( int a, int b ){ return a+b; }

// ●述語その2(関数オブジェクト)
class Minus
{
public:
	int operator()( int a, int b ){ return a-b; }
};
// ●述語その3(関数オブジェクト(内部情報あり))
class PlusAlpha
{
public:
	PlusAlpha( int c ){ m_c = c; }
	int operator()( int a, int b ){ return a+b+m_c; }
private:
	int m_c;
};
// ★実験してみよう
int main( int argc, char* argv[] )
{
  cout<< Calc( 1, 2, Plus )<<endl; // 結果:3
  cout<< Calc( 1, 2, Minus() )<<endl; // 結果:-1  
  cout<< Calc( 1, 2, PlusAlpha(5) )<<endl;// 結果:8 
  return 0;
}

ここで注意して欲しいのは、main()の中、述語MinusとPlusAlphaを呼び出す場合の記述のしかただ。いずれも関数オブジェクトなので、呼び出し時にそのインスタンスを作成している。この3番目に指定する部分にはもちろん、予めどこかで作成された関数オブジェクトインスタンスを指定しても良いし、上記のように呼び出しの際にテンポラリに作成するのでもよい。