読者です 読者をやめる 読者になる 読者になる

【C++】関数オブジェクト(Functor)ってなに?

基本概念

関数オブジェクト(Functor)とはoperator()をメンバに持つクラスのオブジェクトのこと。
関数オブジェクトは一般の関数の代わりに使うこともできる。
関数オブジェクトは、その実行に必要なデータをオブジェクト内に保持することができるので便利な場合がある。

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

struct add_x{
  add_x(int x):x(x){}
  int operator()(int y) const {return x + y;}

private:
  int x;
};

int main(){
  add_x add11(11);
  cout << add11(89) << endl; //100

  // 関数オブジェクトはSTLと相性がよい
  std::vector<int> in;
  for(int i=0;i<10;i++){
    in.push_back(i);
  }
  std::vector<int> out(in.size());
  std::transform(in.begin(), in.end(), out.begin(), add_x(1));
  for(int i=0;i<10;i++){
    cout << in[i] << endl;
  }
}

利点

関数オブジェクトのひとつの利点は状態を保持できる点だ。
上記の例では、main関数のはじめの部分で11を足す関数オブジェクトを作っている。
この11という値は決め打ちではなく、コンストラクタの中で作られているため、任意の値にできる。

別の利点として、STLとの相性が良いというのがある。
stl::transformなどのSTLアルゴリズムに関数オブジェクトを渡せる。
もちろん関数ポインタでも同様なことが可能であるが、関数オブジェクトは状態を保持できるため、カスタマイズが容易であり柔軟性の観点で関数オブジェクトより優れている。

他の利点として、関数オブジェクトをSTLが呼ぶ場合、インライン化が可能であるため、パフォーマンス的にも有利といえる。
それに対して、ポインタの場合には、コンパイラはどの関数を指しているかわからない。そのため実行時に呼ぶこととなる。

(参考)
http://stackoverflow.com/questions/356950/c-functors-and-their-uses