2012-01-29 3 views

答えて

34

関数ポインタは、C++で定義された実際の関数のアドレスです。 std::functionは、任意のタイプの呼び出し可能オブジェクト(関数のように使用できるオブジェクト)を保持できるラッパーです。ここで

struct FooFunctor 
{ 
    void operator()(int i) { 
     std::cout << i; 
    } 
}; 

// Since `FooFunctor` defines `operator()`, it can be used as a function 
FooFunctor func; 
std::function<void (int)> f(func); 

は、std::functionは、それはあなたが、あなたはちょうどそれがvoidを返し、1 intパラメータを持っていることを知って、それはFooFunctorだかわからない—を扱っているが何であるかを呼び出し可能なオブジェクトの種類離れて正確に抽象化することができます。

この抽象化が有用な実際の例は、C++を別のスクリプト言語とともに使用している場合です。 C++で定義された関数とスクリプト言語で定義された関数を汎用的に扱うことができるインターフェイスを設計することもできます。

編集:std::functionと並ん

バインディング、あなたもstd::bindを見つけるでしょう。これらの2つは、一緒に使用すると非常に強力なツールです。その例で

void func(int a, int b) { 
    // Do something important 
} 

// Consider the case when you want one of the parameters of `func` to be fixed 
// You can used `std::bind` to set a fixed value for a parameter; `bind` will 
// return a function-like object that you can place inside of `std::function`. 

std::function<void (int)> f = std::bind(func, _1, 5); 

bindによって返される関数オブジェクトは、最初のパラメータをとり_1、及びaパラメータとしてfuncに渡し、そして一定5ことがbを設定します。

+3

ここに_1は何ですか? – makar

+1

@makarこれは、結果の関数の第1引数を参照するために 'std :: bind'によって使用される識別子です。これは少し似ています: 'void bound(int _1){func(_1、5); } '。 –

+0

[ここのリンク](http://stackoverflow.com/questions/25848690/should-i-use-stdfunction-or-a-function-pointer-in-c)関数ポインタとstd :: functionの間に別の違いがあります:ラムダキャプチャを関数ポインタで使用することはできません。ラムダ '[&](int a、int b){/ * blah * /}'または '[=](int a、int b){/ * blah * /} 'を実行すると、コンパイルエラーが発生します。有効な形式は '[](int a、int b){/ * blah * /}' – r0ng

4

1つは関数ポインタです。もう1つは関数ポインタのラッパーとして機能するオブジェクトです。

彼らはかなりは同じことを表しますが、std::functionはあなたがバインディングやその他もろもろを作るのですかできるように、はるかより強力です。

+0

これらの2つの間で簡単な変換方法がありますか? – phimuemue

+0

@phimuemue:一般的なケースでは意味がありません。 –

+0

@phimuemueデータポインタとしてstd ::関数を使用し、std ::関数を呼び出すラッパー関数を記述します。これを機能させるには、関数ポインタにデータポインタがなければなりません。 – Lalaland

11

std::functionに状態があります。それはそれに "束縛された"追加のパラメータを保持することができます。

これらのパラメータは、他のクラス、他の関数、またはメンバー関数呼び出し用のこのポインタのようなものまでさまざまです。

置換関数ポインタは、それがvoid*std::functionに隠されることになる状態をreperenstingと、typedef int (*fn)(void*,int);あるtypedef int (*fn)(int);

ありません。

40

これらは全く同じではありません。 std::functionは複雑で重く、ステートフルなマジックタイプであり、あらゆる種類の呼び出し可能なエンティティを保持することができますが、関数ポインタは単純なポインタです。あなたがそれを取り除くことができるならば、裸の関数ポインタかauto - bind/auto -lambdaタイプを好むべきです。ファンクション、ファンクタ、ラムダとバインド式のキャプチャなど、呼び出し可能なエンティティの異種コレクションを体系的に編成する体系的な方法が本当に必要な場合は、std::functionを使用してください。


更新:auto種類についての説明のビット:次の2つの関数の比較:

void do_something_1(std::function<void(int)> f, int a) { f(a); } 

template <typename F, typename A> void do_something_2(F f, A a) { f(a); } 

は今ラムダまたはbind表現でそれらを呼び出す想像:

do_something_X([foo, &bar](int n){ bar += n*foo; },  12); 
do_something_X(std::bind(X::bob, &jim, true, _1, Blue), 13); 

テンプレートを使用した2番目のバージョンのほうが効率的です。どちらの場合も、引数Fは実際の、知られていないタイプの式に導かれます。 std::functionの最初のバージョンはテンプレートではなく、より単純でより慎重に見えるかもしれませんが、は常にオブジェクトを構築し、複数タイプの消去と仮想ディスパッチコストを伴う可能性があります。

+0

これはちょっと混乱しています。 つまり、正確にstd :: functionを使用するタイミングと、関数ポインタを使用するタイミングです。また、自動バインド/オートラムダ型とは何ですか? – aCuria

+4

@aCuria:呼び出し可能なもののコンテナを作成し、そこにさまざまな種類の混合型を入れたい場合は、 std :: function'を呼び出してすべてを変換します。しかし、あなたが常に本物のフリー関数を持っていることを知っていれば、関数ポインタのコンテナを作ることができます。実際の投稿の自動設定を少し拡大します。 –

+1

@aCuria:更新済み! –

関連する問題