web-dev-qa-db-ja.com

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

ラムダで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.
72
Anthony Sottile

[&this]が機能しない理由は、構文エラーであるためです。 lambda-introducerの各コンマ区切りパラメーターはcaptureです:

capture:
    identifier
    & identifier
    this

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

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

最初のcapturecapture-defaultにすることができます。

capture-default:
    &
    =

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

5.1.2.7/8:

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

したがって、ラムダは、メンバー名を使用する場合(例では名前xの使用)を囲むメンバー関数の一部であるかのように動作するため、thisの「暗黙の使用」を生成しますメンバー関数のように。

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

したがって、[this][&][=]、または[&,this]lambda-introducerとして使用して、thisポインターを値でキャプチャできます。

ただし、[&this]および[=, this]は不正な形式です。最後のケースでは、gccはエラーではなく[=,this]に対してexplicit by-copy capture of ‘this’ redundant with by-copy capture defaultを許します。

99
Andrew Tomazos

標準には、キャプチャリストに&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が無効であることを保証しています。また、thisのキャプチャーは、*this(これは左辺値、オブジェクト自体)のキャプチャーを意味します参照によるではなくのキャプチャーthisポインター値による

4
陳 力