37

C ++11モードのGCC4.7では、ラムダをとる関数を2つの異なる方法で定義できます。

// by value
template<class FunctorT>
void foo(FunctorT f) { /* stuff */ }

と:

// by r-value reference
template<class FunctorT>
void foo(FunctorT&& f) { /* stuff */ }

だがしかし:

// by reference
template<class FunctorT>
void foo(FunctorT& f) { /* stuff */ }

関数のテンプレートを解除して、代わりにstd ::関数を使用できることはわかっていますが、foo小さくインラインであるため、コンパイラーが内部で行うfの呼び出しをインライン化するための最良の機会を提供したいと思います。最初の2つのうち、ラムダを渡すことが明確にわかっている場合はパフォーマンスに適していますが、最後の1つにラムダを渡すことが許可されないのはなぜですか?

4

3 に答える 3

33

FunctorT&&普遍的な参照であり、右辺値だけでなく、何にでも一致できます。完全な転送を使用できるため、絶対にコピーが必要な場合を除き、C++11 テンプレートで物を渡すのに適した方法です。を介して値にアクセスします。これにより、前にあった場合は右辺値が再度std::forward<FunctorT>(f)作成fされ、そうでない場合は左辺値のままになります。転送の問題について詳しくはこちらstd::forwardをお読みください。また、実際にどのように機能するかについてのステップバイステップのガイドについては、こちらをお読みください。これも興味深い読み物です。std::forward

FunctorT&は単なる左辺値参照であり、一時 (ラムダ式の結果) をそれにバインドすることはできません。

于 2012-09-22T23:56:09.920 に答える
5

ラムダ関数を作成すると、一時オブジェクトが取得されます。非 const 左辺値参照にテンポラリをバインドすることはできません。実際には、ラムダ関数を参照する左辺値を直接作成することはできません。

T&&関数の引数の型を使用して関数テンプレートを宣言すると、関数にオブジェクトをT const&渡す場合、非 const 左辺値オブジェクトを渡す場合、および一時的なものを渡す場合になります。つまり、関数宣言を一時的に渡す場合、オブジェクトを移動せずに渡すことができる右辺値参照を受け取ります。引数を明示的に値で渡す場合、一時オブジェクトは概念的にはコピーまたは移動されますが、このコピーまたは移動は通常省略されます。関数に一時オブジェクトのみを渡す場合、最初の 2 つの宣言は同じことを行いますが、最初の宣言は移動またはコピーを導入する可能性があります。constT&T

于 2012-09-22T23:59:28.300 に答える
3

これは良い質問です-最初の部分:値渡しまたは転送の使用。FunctorT&第二部(議論として)は合理的に答えられたと思います。

私のアドバイスは次のとおりです。関数オブジェクトが事前にわかっている場合にのみ転送を使用して、クロージャー(またはキャプチャリスト)の値を変更します。最良の例:std::shuffle。これは、Uniform Random Number Generator(関数オブジェクト)を取り、ジェネレーターを呼び出すたびにその状態が変更されます。関数オブジェクトはアルゴリズムに転送されます。

それ以外の場合は、値を渡すことをお勧めします。これは、参照によってローカルをキャプチャし、ラムダ関数内でローカルを変更することを妨げるものではありません。それはあなたが思っているように機能します。Dietmarが言うように、コピーのオーバーヘッドはないはずです。インライン化も適用され、参照が最適化される場合があります。

于 2012-09-23T02:50:21.440 に答える