この参照( '&this')をラムダでキャプチャできないのはなぜですか?


91

thisラムダでキャプチャする(オブジェクトプロパティを変更する)正しい方法は次のとおりです。

auto f = [this] () { /* ... */ };

しかし、私が見た次の特異性について興味があります。

class C {
    public:
        void foo() {
            // auto f = [] () { // this not captured
            auto f = [&] () { // why does this work?
            // auto f = [&this] () { // Expected ',' before 'this'
            // auto f = [this] () { // works as expected
                x = 5;
            };
            f();
        }

    private:
        int x;
};

私が混乱している(そして答えたい)奇妙なことは、以下が機能する理由です:

auto f = [&] () { /* ... */ }; // capture everything by reference

そして、なぜ私がthis参照によって明示的にキャプチャできないのか:

auto f = [&this] () { /* ... */ }; // a compiler error as seen above.

6
なぜあなたはしたいですか?ポインタへの参照が役立つthisと思われるものに関しては、変更できない、参照を高速化するのに十分な大きさではない...そしてとにかく実際には存在しないので、実際の寿命はありません。つまり、それへの参照は定義上ぶら下がっています。thisはprvalueであり、lvalueではありません。
underscore_d

回答:


111

[&this]構文エラーであるため、機能しません。内の各コンマ区切りパラメータlambda-introducercapture:です。

capture:
    identifier
    & identifier
    this

&this構文的には許可されていないことがわかります。許可されない理由thisは、小さなconstポインターであるため、参照によってキャプチャする必要がないためです。値で渡したいだけなので、この言語はthis参照によるキャプチャをサポートしていません。

this明示的にキャプチャするには、[this]として使用できますlambda-introducer

最初capturecapture-defaultものは次のとおりです。

capture-default:
    &
    =

これは、参照(&)または値(=)によって、それぞれ使用するものを自動的にキャプチャすることを意味します-ただし、の扱いthisは特別です-どちらの場合も、前述の理由で値によってキャプチャされます(デフォルトのキャプチャでも&、通常は参照によるキャプチャ)。

5.1.2.7/8:

名前ルックアップ(3.4)の目的で、this(9.3.2)のタイプと値を決定し、(*this)(9.3.1)、複合ステートメント[OFを使用して、非静的クラスメンバーを参照するid式をクラスメンバーアクセス式に変換します。THE LAMBDA]は、ラムダ式のコンテキストで考慮されます。

したがって、ラムダは、メンバー名を使用するとき(例ではnameの使用のxように)、それが囲んでいるメンバー関数の一部であるかのように機能するためthis、メンバー関数と同じように「暗黙的な使用法」を生成します。

lambda-captureにcapture-defaultが含まれている場合、lambda-capture&の識別子の前に&。を付けないでください。lambda-captureにcapture-defaultが含まれている場合、lambda-captureには含まれ=ず、含まれ thisている各識別子の前に&。が付きます。識別子またはthisラムダキャプチャに複数回出現してはなりません。

あなたが使用できるように[this][&][=]または[&,this]としてlambda-introducerキャプチャするthis値でポインタを。

ただし[&this][=, this]形式が正しくありません。最後のケースでは、gccはエラー[=,this]explicit by-copy capture of ‘this’ redundant with by-copy capture defaultはなくそれを寛容に警告します。


3
@KonradRudolph:あるものを値で、他のものを参照でキャプチャしたい場合はどうなりますか?または、キャプチャしたものを非常に明確にしたいですか?
xeo 2013年

2
@KonradRudolph:これは安全機能です。意図しない名前を誤ってキャプチャする可能性があります。
Andrew Tomazos 2013年

8
@KonradRudolph:ブロックレベルの構造体は、使用するオブジェクトへのポインターを、式でオブジェクト名を使用するだけで、囲んでいるスコープを存続できる新しい非表示の匿名型に魔法のようにコピーしません。ラムダの捕獲はもっと危険な仕事です。
Andrew Tomazos 2013年

5
@KonradRudolph「[&]制御構造に渡されるブロックを作成するようなことをしている場合に使用します」と言いますが、それほど単純ではない目的で使用されるラムダを生成している場合は明示的にキャプチャします。 [&]ラムダが現在のスコープよりも長生きする場合、これは恐ろしい考えです。ただし、ラムダの多くの使用法は、ブロックを制御構造に渡す方法にすぎず、ブロックはスコープ内で作成されたブロックよりも長生きしません。
Yakk-Adam Nevraumont 2013年

2
@Ruslan:いいえ、thisキーワードでthisあり、識別子ではありません。
Andrew Tomazos 2016年

6

標準には&thisキャプチャリストにないため:

N4713 8.4.5.2キャプチャ:

lambda-capture:
    capture-default
    capture-list
    capture-default, capture-list

capture-default:
    &
    =
capture-list:
    capture...opt
    capture-list, capture...opt
capture:
    simple-capture
    init-capture
simple-capture:
    identifier
    &identifier
    this
    * this
init-capture:
    identifier initializer
    &identifier initializer
  1. ラムダキャプチャの目的で、式は次のようにローカルエンティティを参照する可能性があります。

    7.3この式は潜在的に* thisを参照します。

したがって、標準は保証しthis*this有効であり、&this無効です。また、キャプチャとは、ポインタを値キャプチャするのではなく、参照によって(左辺値、オブジェクト自体)をキャプチャthisすることを意味します*thisthis


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