C++ ファンクタとその用途は何ですか? 質問する

C++ ファンクタとその用途は何ですか? 質問する

C++ の関数についてよく耳にします。関数とは何か、またどのような場合に役に立つのか、概要を教えていただけますか?

ベストアンサー1

ファンクタは、 を定義するクラスですoperator()。これにより、関数のように見えるオブジェクトを作成できます。

// this is a functor
struct add_x {
  add_x(int val) : x(val) {}  // Constructor
  int operator()(int y) const { return x + y; }

private:
  int x;
};

// Now you can use it like this:
add_x add42(42); // create an instance of the functor class
int i = add42(8); // and "call" it
assert(i == 50); // and it added 42 to its argument

std::vector<int> in; // assume this contains a bunch of values)
std::vector<int> out(in.size());
// Pass a functor to std::transform, which calls the functor on every element 
// in the input sequence, and stores the result to the output sequence
std::transform(in.begin(), in.end(), out.begin(), add_x(1)); 
assert(out[i] == in[i] + 1); // for all i

ファンクタには、いくつかの優れた点があります。1 つは、通常の関数とは異なり、状態を含めることができることです。上記の例では、与えられた値に 42 を加算する関数を作成します。ただし、その値 42 はハードコードされているわけではなく、ファンクタ インスタンスの作成時にコンストラクター引数として指定されています。コンストラクターを別の値で呼び出すだけで、27 を加算する別の加算器を作成できます。これにより、ファンクタをうまくカスタマイズできます。

最後の行が示すように、関数は std::transform や他の標準ライブラリ アルゴリズムなどの他の関数に引数として渡されることがよくあります。通常の関数ポインターでも同じことができますが、上で述べたように、関数は状態を含むため「カスタマイズ」でき、より柔軟になります (関数ポインターを使用する場合は、引数に正確に 1 を追加する関数を作成する必要があります。関数は汎用的で、初期化したものを追加します)。また、より効率的である可能性もあります。上記の例では、コンパイラーはどの関数をstd::transform呼び出す必要があるかを正確に把握しています。 を呼び出す必要がありますadd_x::operator()。つまり、その関数呼び出しをインライン化できます。これにより、ベクトルの各値で関数を手動で呼び出した場合と同じくらい効率的になります。

代わりに関数ポインタを渡した場合、コンパイラはそれがどの関数を指しているかをすぐには確認できないため、かなり複雑なグローバル最適化を実行しない限り、実行時にポインタを逆参照してから呼び出しを行う必要があります。

おすすめ記事