関数オブジェクト
関数オブジェクトは、LISPにおいてその初期から研究された。計算機プログラムの構造と解釈の第3章でも解説されている。
オブジェクト指向言語では、Smalltalk において、ブロックが関数オブジェクトの記法となるよう設計された。たとえば配列の各要素を通常の大小関係とは違う順序で並べ替えたい場合、比較のための関数オブジェクトを引数に取るソートメソッドを、引数としてブロックを付けて、呼び出す。ブロック内には、カスタマイズ版の比較手続きを記述する。ソートメソッド内での比較は、渡された関数オブジェクトの手続きを呼び出すことで行なわれ、期待する大小関係でのソートが行なわれる。これは、Strategyデザインパターンの完全な具現化であり、着脱可能 (pluggable) な振る舞いを促進するものである。
ここで説明するのは C++ 用語のファンクタではない。
より形式化したものとして、数学(圏論)における関手(ファンクタ)と同様のものを持つ言語もある。たとえば、Standard MLのfunctorは、モジュールからモジュールへのマッピング である。
HaskellのFunctorは以下のような型クラスである。
Prologでは、関数のシンボルをファンクタと呼んでいる。
↑ C++ FAQ [33.15] What's the difference between a functionoid and a functor?
↑ スクリプトを記述する上では簡単なように設計されているが、内部ではわりとコストが掛かる。ブロックはエスケープしないため軽い処理で扱うことができるし、元々イテレータのためのものだったため、繰り返し処理のために使われることからも、軽いほうが望ましい。それがオブジェクトになれば、メソッドの返り値などになり得るために、重い処理となるためである。
C++では、クラスあるいは構造体において関数呼び出し演算子の多重定義が可能となっている。具体的には、任意の引数を持つoperator()メンバー関数を定義することで、そのオブジェクトのインスタンスを指す変数の名前が、あたかも関数名(関数指示子)であるかのような構文で、定義した関数を呼ぶことができる。このような C++ のオブジェクトを、C++ の用語ではファンクタ (functor) と呼ぶ(#C++のファンクタとファンクショノイド を参照)。
C++のclass/structは、デフォルトのアクセスレベル(アクセス修飾子(英語版))がprivate/publicであるという違いしかないため、関数オブジェクトの記述ではclassの代わりにstructが使われることも多い。
配列の中から特定の条件に該当する要素の個数を数えるルーチンの例を考えてみよう。ただし条件の判定処理は自由にカスタマイズできるものとする。
関数へのポインタを使用する C のプログラムは、たとえば下記のようになる。
一方、C++の関数オブジェクトを利用すると下記のようになる。