lvalue
ラムダクロージャーは常にrvalue
関数パラメーターとして渡すことができることがわかりました。
次の簡単なデモをご覧ください。
#include <iostream>
#include <functional>
using namespace std;
void foo(std::function<void()>&& t)
{
}
int main()
{
// Case 1: passing a `lvalue` closure
auto fn1 = []{};
foo(fn1); // works
// Case 2: passing a `lvalue` function object
std::function<void()> fn2 = []{};
foo(fn2); // compile error
return 0;
}
ケース2は標準的な動作です(デモ目的でstd::function
を使用しただけですが、他のタイプも同じように動作します)。
ケース1はどのように、そしてなぜ機能するのですか?関数が返された後のfn1
クロージャの状態は何ですか?
ケース1はどのように、そしてなぜ機能するのですか?
foo
を呼び出すには、rvalue参照にバインドするstd::function<void()>
のインスタンスが必要です。 std::function<void()>
は、void()
シグネチャと互換性のある任意の呼び出し可能なオブジェクトから構築できます。
まず、一時的なstd::function<void()>
オブジェクトが_[]{}
_から作成されます。使用されるコンストラクターは#5 here で、クロージャーを_std::function
_インスタンスにコピーします。
_template< class F > function( F f );
_ターゲットを
std::move(f)
で初期化します。f
が関数へのNULLポインターまたはメンバーへのNULLポインターである場合、_*this
_は呼び出し後に空になります。
次に、一時的なfunction
インスタンスが右辺値参照にバインドされます。
関数が返された後のfn1クロージャの状態は何ですか?
以前と同じですが、_std::function
_インスタンスにコピーされたためです。元の閉鎖は影響を受けません。
ラムダはstd::function
ではありません。参照は直接をバインドしません。
ケース1は、ラムダがstd::function
sに変換できるため機能します。これは、一時的なstd::function
がcopyingfn1
によって具体化されることを意味します。この一時変数は右辺値参照にバインドできるため、引数はパラメーターと一致します。
また、コピーがfn1
がfoo
で発生するすべての影響を受けない理由でもあります。
関数が返された後のfn1クロージャの状態は何ですか?
fn1
は何もキャプチャしないため、ステートレスです。
ケース1はどのように、そしてなぜ機能するのですか?
これは、引数が参照される右辺値の型とは異なる型であるため機能します。タイプが異なるため、暗黙的な変換が考慮されます。ラムダはこのstd::function
の引数に対してCallableであるため、std::function
のテンプレート変換コンストラクタを介して暗黙的にラムダに変換できます。変換の結果はprvalueであるため、rvalue参照とバインドできます。