関数オブジェクト(Function Object)

関数オブジェクトとはoperator()を持つオブジェクトです。関数オブジェクトはアルゴリズムのカスタマイザとして機能します。関数オブジェクトの交換によってアルゴリズムに様々な処理を行なわせることができます。STLの関数オブジェクトはoperator()の引数が1つのものと2つのものがあり、それぞれunary_function,binary_functionのサブクラスとなっています。operator()の値がboolとコンパチブルである、すなわち"〜である"かどうかを判定するために用いられる関数オブジェクトを"述語オブジェクト"(Predicate)といいます。

[演算オブジェクト]

STLは四則演算、比較演算、論理演算を行なう関数オブジェクトを提供しています:

[関数アダプタ]

[関数オブジェクトの使い方]

関数オブジェクトは多くの場合アルゴリズムの引数として用いられます。
 // 例: アルゴリズムfind_if
 template<class InputIterator, class Predicate>
 InputIterator
 find_if(InputIterator first, InputIterator last, Predicate pred) {
    while ( first != last && !pred(*first) )
      ++first;
    return first;
 }
find_ifはfirstから始まりlastに達しない範囲にあるイテレータiに対し、pred(*i) != false となるiを返します。int配列の中から0より大きい要素を探すには、operator()に引数として渡された値が0より大きければtrueを返す関数オブジェクトをfind_ifの第3引数に与えます:
 bool positive(int x) { return x > 0; }

 int array[] = { 0, 0, -1, 3, 0 };
 int* it = find_if(array, array+5, &positive);
 if ( it != array+5 ) {
   // 見つかった!
 }
この例では関数のポインタを関数オブジェクトとして与えています。関数のポインタfに対してf()するとその関数が呼び出されて結果を返すのでoperator()が定義されているとみなせるからです。

[バインダ]

上の例において比較演算を行なう関数オブジェクトgreater<T>を使うことはできないのでしょうか。find_ifの引数に与える関数オブジェクトpredはoperator()の引数が1つでなくてはなりません。ところがgreater<T>は引数を2つ要求します。positive(x)がその内部でgreater<T>::operator()(x,0)を呼んでくれるような関数オブジェクトpositiveがあるなら、greater<T>からpositiveを作り出すことができます。binder1st,binder2ndはまさしくそのために用意された関数オブジェクトです。
  binder2nd< greater<int> > positive(greater<int>(),0);
  int array[] = { 0, 0, -1, 3, 0 };
  int* it = find_if(array, array+5, positive);
  if ( it != array+5 ) {
    // 見つかった!
  }
binder1stのコンストラクタには2引数の関数オブジェクトopと、あらかじめ与える引数yを与えます。するとoperator()(const T& x)はop(y,x) (binder2ndはop(x,y))を返します。

binder1st,binder2ndを手軽に扱えるよう、関数bind1st,bind2ndが用意されています。関数bind1st,bind2ndはbinary_functionと引数からbinder1st,binder2ndのインスタンスを作ってくれます。

  int array[] = { 0, 0, -1, 3, 0 };
  int* it = find_if(array, array+5, bind2nd(greater<int>(),0));
  if ( it != array+5 ) {
    // 見つかった!
  }

[関数ポインタ・アダプタ]

ではこんな例はどうでしょう:
  // y[i] = x[i]^2.5
  double x[10],y[10];
  transform(x, x+10, y, bind2nd(&pow,2.5));
標準関数 double pow(double,double) へのポインタを関数オブジェクトとしてbind2ndに与えています。残念ながらこのコード、コンパイルエラーとなります。bind2ndの第1引数はbinary_functionのサブクラスでなくてはならないからです。関数ポインタをフォーマルな関数オブジェクト(unary_function/binary_functionのサブクラス)に変換するのがpointer_to_unary_function/pointer_to_binary_functionです。
  double x[10], y[10];
  pointer_to_binary_function<double,double,double> power(&pow);
  transform(x, x+10, y, bind2nd(power,2.5));
バインダと同様に、関数ポインタから関数オブジェクトを生成する関数ptr_funが用意されています。
  double x[10], y[10];
  transform(x, x+10, y, bind2nd(ptr_fun(&pow),2.5));
関数オブジェクトを使った例をもうひとつ示しましょう。100より小さな素数を求めるプログラムです。余りを求めるmodulus、binder1stを生成するbind1st、そして述語オブジェクトの結果を否定するアダプタunary_negateを生成するnot1を使っています。
  // primes.cpp
  #include <iostream>   // cout
  #include <algorithm>  // find_if
  #include <functional> // function objects

  using namespace std;

  int main() {
    const int N = 100;
    int primes[N] = { 2, 3, 5, 7, 11 }; // 素数表
    int* result = primes+5;
    for ( int i = 13; i < 100; i +=2 )
      // i が 2,3,5,7.11 で割り切れないなら i は素数だ。
      if ( find_if(primes, primes+5, not1(bind1st(modulus<int>(),i)))
           == primes+5 )
        *result++ = i; // 素数表に追加

    // 素数表を出力
    for ( int* it = primes; it != result; ++it )
      cout << *it << ' ';

    return 0;
  }

  実行結果:
    2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79
    83 89 97

[関数オブジェクトの作り方]

関数オブジェクトは最低限 operator() が定義されていなければなりません。関数オブジェクトを作るには、定義するoperator()の引数が1つのときはunary_function<引数の型,戻り値の型>、引数が2つのときはbinary_function<第1引数の型,第2引数の型,戻り値の型>をベースクラスとします。

そしてoperator()は引数が1つすなわちunary_function<Arg,Result>のサブクラスであれば

 Result operator()(const Arg&) const;
引数が2つすなわちbinary_function<Arg1,Arg2,Result>のサブクラスであれば
 Result operator()(const Arg1&, const arg2) const;
のプロトタイプに従います。
  /*
   * ユーザ定義関数オブジェクトのひな型
   */

  // 単項関数
  class UFUN : public unary_function<ARG,RESULT>
  public:
    // 必要に応じてコンストラクタ/デストラクタ/コピー演算子を定義すること。
    RESULT operator()(const ARG&) const;
  };

  // 二項関数
  class BFUN : public binary_function<ARG1,ARG2,RESULT>
  public:
    // 必要に応じてコンストラクタ/デストラクタ/コピー演算子を定義すること。
    RESULT operator()(const ARG1&, const ARG2&) const;
  };
例として与えられた数が偶数であるか否かを判定する関数オブジェクトis_evenを作ります。 is_evenのインスタンスをfとすると、
 f(x) ... true  (xが偶数のとき)
 f(x) ... false (xが偶数でないとき)
となるようなoperator()が定義されていればよいわけです。したがってoperator()の戻り値はbool、そして引数は2で割った余りを求めることのできる任意の型となります。
  template<class T>
  struct is_even : unary_function<T,bool> {
    bool operator()(const T& x) const {
      return x % 2 == 0;
    }
  }
is_even、それと条件を満たす要素の数を求めるアルゴリズムcount_ifを使ってコンテナ内にある偶数の数を求めてみましょう:
  // 配列の中にある偶数の個数を数える
  int iv[7] = { 0, 1, 2, 3, 4, 5, 6 };
  is_event<int> f;
  int n = count_if(iv, iv+7, f);
  // 上の2行は、
  // int n = count_if(iv, iv+7, is_even<int>()); でもよい
関数オブジェクトは通常の関数のように使うこともできるし、アルゴリズムに与えることもできます
  // 複素平面上の点xを、原点を中心としてtheta[ラジアン]回転する。
  struct point_rotate
    : binary_function< complex<double>,double,complex<double> > {
    typedef complex<double> C;
    C operator()(const C& x, double theta) const {
      double s = sin(theta);
      double c = cos(theta);
      return C(c*x.real() - s*x.imag(), s*x.real() + c*x.imag());
   }
  };

  inline double deg2rad(double theta) {
    return theta / 180.0 * 3.1415927;
  }

  int main() {
    typedef complex<double> C;
    point_rotate rot;
    C x(4,5);
    cout << x << " を90度回転させると " << rot(x,deg2rad(90)) << endl;
    C p[] = { C(0,0), C(3,4), C(5,5) };
    iter_print(p,p+3); // 巻末を参照
    cout << "... を90度回転させると ..." << endl;
    transform(p, p+3, p, bind2nd(point_rotate(),deg2rad(90)));
    iter_print(p,p+3);
    return 0;
  }

  実行結果:
    (4,5) を90度回転させると (-5,4)
    [(0,0) (3,4) (5,5)]
    ... を90度回転させると ...
    [(0,0) (-4,3) (-5,5)]
コンストラクタやメンバ関数を使って付加条件を与えることもできます:
  // ax^2+bx+c
  template<class T>
  struct axx_bx_c : unary_function<T,T> {
    T a,b,c;
    axx_bx_c() : a(0),b(0),c(0) {}
    axx_bx_c(const T& aa, const T& bb, const T& cc)
      : a(aa), b(bb), c(cc) {}
    T operator()(const T& x) const {
      return a*x*x+b*x+c;
    }
  }

  axx_bx_c<double> f(2,3,4); // f(x) : 2x^2+3x+4
  for ( int x = 0; x < 10; ++x )
    cout << f((double)x)) << endl;
コンストラクト時に関数オブジェクトf,gを与えておいて、operator()(x)がf(g(x))を返す関数アダプタunary_composeを作ってみます。このときunary_compose::operator()の引数の型はg()の引数の型、戻り値の型はf()の戻り値の型となりますから:
 template<class Op1, class Op2>
 class unary_compose
   : public unary_function<Op1::argument_type, Op2::result_type> {
   Op1 op1;
   Op2 op2;
 public:
   unary_compose(const Op1& f, const Op2& g) : op1(f), op2(g) {}
   Op2::result_type operator()(const Op2::argument_type& x) const [
     return op1(op2(x));
   }
 };
unary_compseを使って-x*xを計算するオブジェクトを作ると:
 template<class T>
 struct square : unary_function<T,T> {
   T operator()(const T& x) const {
     return x*x;
   }
 };

 // array[n] = -array[n]*array[n] (n=0..N-1)
 double array[N];
 transform(array, array+N, array,
           unary_compose< negate<double>,square<double> >
             (negate<double>(),square<double>()));
transformに与えている関数オブジェクトの指定がかなりややこしいですね。関数オブジェクトを生成するヘルパ関数を用意しておくといいでしょう:
template<class Op1, class Op2>
inline unary_compose<Op1,Op2>
compose1(const Op1& f, const Op2& g) {
  return unary_compose<Op1,Op2>(f,g);
}
ヘルパ関数compose1を使えば:
 // array[n] = -array[n]*array[n] (n=0..N-1)
 double array[N];
 transform(array, array+N, array,
           compose1(negate<double>(),square<double>()));
  /*
   * ユーザ定義 関数オブジェクトの例
   */

  //--- 単項 '==' : unary_equal_to / eq -------------------
  template<class T>
  struct unary_equal_to : std::unary_function<T,bool> {
    T value;
    explicit unary_equal_to(const T& v) : value(v) {}
    bool operator()(const T& x) const
      { return x == value; }
  };

  template<class T>
  inline unary_equal_to<T>
  eq(const T& value) { return unary_equal_to<T>(value); }

  //--- 単項 '!=' : unary_not_equal_to / ne ---------------
  template<class T>
  struct unary_not_equal_to : std::unary_function<T,bool> {
    T value;
    explicit unary_not_equal_to(const T& v) : value(v) {}
    bool operator()(const T& x) const
      { return !(x == value); }
  };

  template<class T>
  inline unary_not_equal_to<T>
  ne(const T& value)
    { return unary_not_equal_to<T>(value); }

  //--- 単項 '<' : unary_less / lt -------------------------
  template<class T>
  struct unary_less : std::unary_function<T,bool> {
    T value;
    explicit unary_less(const T& v) : value(v) {}
    bool operator()(const T& x) const
      { return x < value; }
  };

  template<class T>
  inline unary_less<T>
  lt(const T& value)
    { return unary_less<T>(value); }

  //--- 単項 '>' : unary_greater / gt ---------------------
  template<class T>
  struct unary_greater : std::unary_function<T,bool> {
    T value;
    explicit unary_greater(const T& v) : value(v) {}
    bool operator()(const T& x) const
      { return value < x; }
  };


  template<class T>
  inline unary_greater<T>
  gt(const T& value)
    { return unary_greater<T>(value); }

  //--- 単項 '<=' : unary_less_equal / le -----------------
  template<class T>
  struct unary_less_equal : std::unary_function<T,bool> {
    T value;
    explicit unary_less_equal(const T& v) : value(v) {}
    bool operator()(const T& x) const
      { return !(value < x); }
  };

  template<class T>
  inline unary_less_equal<T>
  le(const T& value)
    { return unary_less_equal<T>(value); }

  //--- 単項 '>=' : unary_greater_equal / ge --------------
  template<class T>
  struct unary_greater_equal : std::unary_function<T,bool> {
    T value;
    explicit unary_greater_equal(const T& v) : value(v) {}
    bool operator()(const T& x) const
      { return !(x < value); }
  };

  template<class T>
  inline unary_greater_equal<T>
  ge(const T& value)
    { return unary_greater_equal<T>(value); }