7

私は読んでいてboost::function、その使用法と、ドキュメントで見つけた他のC++構造または用語との関係について少し混乱しています

boost::functionC ++(C ++ 11)のコンテキストでは、のインスタンス、関数オブジェクト関数、およびラムダ式の違いは何ですか?いつどの構成を使用する必要がありますか?たとえばboost::function、オブジェクトを直接使用するのではなく、いつ関数オブジェクトをラップする必要がありますか?

上記のすべてのC++は、関数型言語でクロージャと呼ばれるものを実装するためのさまざまな方法を構築していますか(値として渡され、他の関数によって呼び出される可能性のある、キャプチャされた変数を含む関数)?

4

3 に答える 3

6

関数オブジェクトとファンクターは同じものです。関数呼び出し演算子を実装するオブジェクトoperator()。ラムダ式は関数オブジェクトを生成します。boost::function/の特殊化のタイプをstd::function持つオブジェクトも関数オブジェクトです。

ラムダは、ラムダ式が匿名で一意の型を持っているという点で特別であり、ファンクターをインラインで作成するための便利な方法です。

boost::function/std::functionは、呼び出し可能なエンティティを、呼び出し可能なエンティティの署名のみに依存するタイプのファンクターに変換するという点で特別です。たとえば、ラムダ式はそれぞれ一意の型を持っているため、ジェネリック以外のコードに渡すことは困難です。ラムダからを作成する場合はstd::function、ラップされたラムダを簡単に渡すことができます。

于 2012-10-10T14:05:50.133 に答える
6

boost::functionと標準バージョンstd::functionはどちらも、ライブラリによって提供されるラッパーです。それらは潜在的に高価でかなり重いので、実際に異種の呼び出し可能なエンティティのコレクションが必要な場合にのみ使用する必要があります。一度に1つの呼び出し可能なエンティティのみが必要である限り、autoまたはテンプレートを使用する方がはるかに優れています。

次に例を示します。

std::vector<std::function<int(int, int)>> v;

v.push_back(some_free_function);           // free function
v.push_back(&Foo::mem_fun, &x, _1, _2);    // member function bound to an object
v.push_back([&](int a, int b) -> int { return a + m[b]; });  // closure

int res = 0;
for (auto & f : v) { res += f(1, 2); }

反例は次のとおりです。

template <typename F>
int apply(F && f)
{
    return std::forward<F>(f)(1, 2);
}

applyこの場合、次のように宣言することは完全に無償でした。

int apply(std::function<int(int,int)>)   // wasteful

変換は不要であり、テンプレート化されたバージョンは、実際の(多くの場合不明な)タイプ、たとえばバインド式やラムダ式と一致する可能性があります。

于 2012-10-10T14:22:37.513 に答える
3

関数オブジェクトとファンクターは、多くの場合、概念の観点から説明されます。つまり、あるタイプの一連の要件を記述しているということです。ファンクターに関する多くのことがC++11で変更され、新しい概念はと呼ばれてCallableいます。呼び出し可能タイプのオブジェクトoは、(本質的に)式o(ARGS)が真であるオブジェクトです。の例Callable

int f() {return 23;}

struct FO {
  int operator()() const {return 23;}
};

多くの場合、の返品タイプに関するいくつかの要件Callableも追加されます。Callable次のように使用します。

template<typename Callable>
int call(Callable c) {
  return c();
}

call(&f);
call(FO());

上記のような構成では、コンパイル時に正確な型を知っている必要があります。これは常に可能であるとは限らず、ここで問題 std::functionが発生します。

std::functionはそのようなCallableものですが、呼び出している実際の型を消去することができます(たとえば、呼び出し可能オブジェクトを受け入れる関数はテンプレートではなくなりました)。それでも関数を呼び出すには、その引数と戻り型を知っている必要があります。したがって、これらはのテンプレート引数として指定する必要がありますstd::function

次のように使用します。

int call(std::function<int()> c) {
  return c();
}

call(&f);
call(FO());

使用するとパフォーマンスに影響を与える可能性があることを覚えておく必要がありますstd::function。使用する必要があるのは、必要であると確信できる場合のみにしてください。他のほとんどすべての場合、テンプレートが問題を解決します。

于 2012-10-10T14:25:02.220 に答える