ラムダクロージャの左辺値を右辺値参照パラメータとして渡すことができます


18

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関数が返された後の閉鎖の状態はどうですか?


5
私はので、それがあると思いfn1暗黙的に変換されるstd::functionの中でfoo(fn1)。その一時的な関数は右辺値です。
eike

@RichardCritten本当にわからなかったので、答えを投稿しませんでした。今はもう一つは必要ないと思います。
eike

1
@eike np私はしばしば同じように感じ、多くの答えをうんざりしています。
Richard Critten

2
@Sumudu質問の内容がわからなかったため、質問した人はあなたを惑わしました。彼らが尋ねるつもりだったのは、「なぜテンプレートの引数をstd::functionラムダから推定できないのか」ということでした。プログラムはのテンプレート引数を推定しようとしないstd::functionので、暗黙の変換に問題はありません。
eerorika

1
リンクした質問のタイトルは少し誤解を招くものです。std::functionラムダクロージャを受け入れる非明示的なコンストラクタがあるため、暗黙の変換があります。ただし、リンクされた質問の状況では、のテンプレートのインスタンス化はstd::functionラムダ型から推測できません。(例えば、std::function<void()>から構成することができる[](){return 5;}、それがvoid以外の戻り値の型を持っているにもかかわらず。
アイケ

回答:


8

ケース1はどのように、そしてなぜ機能するのですか?

呼び出すにfooは、右辺値参照にstd::function<void()>バインドするのインスタンスが必要です。署名と互換性のある任意の呼び出し可能なオブジェクトから構築できますstd::function<void()>void()

まず、一時std::function<void()>オブジェクトがから作成され[]{}ます。使用されるコンストラクターは、#5 hereで、std::functionインスタンスにクロージャーをコピーします。

template< class F >
function( F f );

ターゲットをで初期化しstd::move(f)ます。fが関数へのヌルポインターまたはメンバーへのヌルポインターである場合*this、呼び出し後は空になります。

次に、一時functionインスタンスが右辺値参照にバインドされます。


関数が返された後のfn1クロージャの状態は何ですか?

std::functionインスタンスにコピーされたため、以前と同じです。元の閉鎖は影響を受けません。


8

ラムダはではありませんstd::function。参照は直接バインドしません。

ラムダはstd::functionsに変換できるため、ケース1が機能します。これは、一時ファイルがコピーstd::functionによって具体化されることを 意味しfn1ます。上記の一時変数は右辺値参照にバインドできるため、引数はパラメーターと一致します。

また、コピーはfn1、で発生することによる影響をまったく受けない理由でもありfooます。


5

関数が返された後のfn1クロージャの状態は何ですか?

fn1 何もキャプチャしないため、ステートレスです。

ケース1はどのように、そしてなぜ機能するのですか?

これは、引数が参照される右辺値の型とは異なる型であるため機能します。タイプが異なるため、暗黙的な変換が考慮されます。ラムダはthisの引数に対してCallableであるため、std::functionのテンプレート変換コンストラクタを通じて暗黙的に変換できstd::functionます。変換の結果はprvalueであるため、rvalue参照とバインドできます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.