ラムダ・キャプチャーの理解

ラムダ式では、ラムダ式外で宣言された識別子を参照することができます。識別子がローカル変数または自動記憶域期間での参照の場合、上位レベルの参照であり、ラムダ式によって「キャプチャー」されなければなりません。そのようなラムダ式は、[lambda-captureopt] によって導入されます。lambda-captureopt は、識別子を参照によってキャプチャーするか、コピーによってキャプチャーするかを指定します。次の表は、lambda-captureopt の形式をまとめたものです。

シンボル

意味

[]

キャプチャーなし: 上位レベルの参照はエラーです。

[&x, y, ...]

指定どおりにキャプチャー: & プリフィックスが付加されている識別子は、参照でキャプチャーされます。その他の識別子は、コピーによってキャプチャーされます。明示的にリストされていない変数への上位レベルの参照はエラーです。

[&]

参照でキャプチャー: 上位レベルの参照は暗黙的に変数を参照でキャプチャーします。

[=]

コピーでキャプチャー: 上位レベルの参照は暗黙的に変数をコピーでキャプチャーします。

[&, x, y, ...]

参照でキャプチャー (例外あり): リストされた変数は、値/コピー (リストされていない変数は & プリフィックスが付加されています) でキャプチャーされます。

[=, &x, &y, ...]

コピーでキャプチャー (例外あり): リストされた変数は、参照でのみキャプチャーされます (リストされた変数にはすべて & プリフィックスが付加されていなければなりません)。

リストでは、識別子が 2 度リストされることはありません。area を 4 つの円の面積の合計にセットする次のコード例では、[&area,pi] は、参照で area が、コピーで pi がキャプチャーされることを示しています。

float radius[] = {2,3,5,7};

float area=0;

float pi = 3.14f;

for_each(radius, radius+4, [&area,pi](float r) {return area+=pi*r*r;})

デフォルト・キャプチャーの指定

デフォルト・キャプチャーを指定する場合は、リストではもう一方の種類のキャプチャーのみを指定する必要があります。つまり、デフォルト・キャプチャーを参照で指定した場合は、コピーでキャプチャーされる変数をリスト (リストのみ) しなければなりません。例えば、参照で x を、コピーで y をキャプチャーし、xy の両方が関数本体にある場合の正しいコードと誤ったコードを次に示します。

[&,&x,y]

 //ERROR - default is capture-by-reference; list only capture-by-copy variable, y

 

[&,y]

 //CORRECT - default is capture-by-reference; listed variable, y, should not have & prefix

 

[=,&x,y]  

 //ERROR - default is capture-by-copy; listed variable, x, must be prefixed with &

 

[=,&x]  

 //CORRECT - default is capture by copy; listed variable must be prefixed with &

 

[&x]   

 //ERROR - no default capture; you must list y separately to be captured by copy

 

[y]    

 //ERROR - again no default capture is specified, so you must list &x separately to be captured by reference

 

[&x,y]   

 //CORRECT - since no default is specified, every variable is listed with its capture mode.

デフォルト・バインド・モード

次のラムダ式は、デフォルト・バインド・モードを示しています。3 つの式はすべてセマンティクス的に等価です。それぞれの式で xy は参照によりキャプチャーされ、ab はコピーによりキャプチャーされます。

[&x,&y,a,b](float r) {x=a; y=b;}

 

[&,a,b](float r) {x=a; y=b;}

 

[=,&x,&y](float r) {x=a; y=b;}

this の参照

ラムダ式がメンバー関数の中にある場合、this を参照できます。this は変数ではないため、参照によりキャプチャーすることはできません。[&] によってラムダ式で暗黙的にキャプチャーされても、それはコピーによりキャプチャーされます。