lambda の概要
Python に慣れているプログラマーは、lambda についてもよく知っているはずです。簡単に言えば、ラムダは匿名で呼び出し可能なコードのブロックです。新しい C++11 標準では、ラムダの形式は次のとおりです:
[capture list] (parameter list) -> return type { function body }
ご覧のとおり、4 つのコンポーネントがあります:
1.キャプチャ リスト: キャプチャ リスト
2.パラメータ リスト: パラメータ リスト
3.return type: 戻り値の型
4.function body: 実行コード
このうち、パラメータリストと戻り値の型は無視して構いません。
以下、いくつかの簡単な例を見てみましょう:
auto f1 = [] { return 1; }; auto f2 = [] () { return 2; }; cout<<f1()<<'\t'<<f2()<<endl;
キャプチャ リスト
ラムダのキャプチャ リストは、値と参照の両方をキャプチャできます。
キャプチャ値:
int test_data[] = {1, 5, 9, 7, 3, 19, 13, 17}; int border = 8; auto f3 = [border](const int &i){ if(i > border) cout<<i<<'\t'; }; for_each(begin(test_data), end(test_data), f3); cout<<endl;
キャプチャ参照:
auto f4 = [&border](const int &i){ if(i > border) cout<<i<<'\t'; }; border = 6; for_each(begin(test_data), end(test_data), f4); cout<<endl;
出力からわかるように、ラムダで機能する境界線は変更された 6 であり、キャプチャが実際に参照であることを確認します。
参照をキャプチャするときは、ラムダが呼び出されたときにこの参照がまだ有効であることを確認する必要があることに注意してください。
キャプチャ リストでは暗黙的なキャプチャも使用できます。これにより、コンパイラはラムダ実行コードを通じてどのローカル変数をキャプチャする必要があるかを判断できます。
暗黙的キャプチャでは、値、参照、またはその 2 つの混合をキャプチャできます:
char space = ' '; auto f5 = [=](const int &i){ if(i > border) cout<<i<<'\t'; }; auto f6 = [&](const int &i){ if(i > border) cout<<i<<'\t'; }; auto f7 = [&, space](const int &i){ if(i > border) cout<<i<<space; }; border = 0; for_each(begin(test_data), end(test_data), f5); cout<<endl; for_each(begin(test_data), end(test_data), f6); cout<<endl; for_each(begin(test_data), end(test_data), f7); cout<<endl;
ここで f7 で使用される混合形式は、「スペース キャプチャ値を除き、他の変数は参照をキャプチャする」と解釈できます。
変数ラムダ
ラムダが値によってキャプチャされた変数の値を変更する必要がある場合、mutable キーワードをラムダに追加する必要があります。そうしないとコンパイルエラーが発生します。
auto f8 = [&, space](const int &i) mutable { if(i > border) {cout<<i<<space; space='\t';} }; for_each(begin(test_data), end(test_data), f8); cout<<endl; cout<<1<<space<<2<<endl;
出力からわかるように、最初の呼び出しの後、ラムダ f8 のスペースの値はタブ文字 Tab に変換されましたが、ラムダの外ではスペースは依然としてスペースです。
戻り型
ラムダの戻り型は末尾戻り型方式を採用しています。一般:
1. lambda に return ステートメントのみが含まれる場合、コンパイラーはその戻り値の型を推論でき、現時点では戻り値の型を明示的に指定する必要はありません。
2. それ以外の場合、コンパイラーは lambda が返すものであると想定します。 void および void を返す 関数は特定の値を返すことができませんが、これはほとんどの場合矛盾するため、戻り値の型を明示的に指定する必要があります。
しかし、実際のテストの後、現在の g++ コンパイラーはより賢いです。ポイント 2 については、現時点では、コンパイラーがラムダ関数本体から関数の戻り値の型を推論できる限り、戻り値の型を明示的に指定する必要はありません。例:
auto f9 = [](const int i){if(i % 3) return i * 3; else return i;}; transform(begin(test_data), end(test_data), begin(test_data), f9); border = 0; for_each(begin(test_data), end(test_data), f6); cout<<endl;
ラムダ コード ブロックには複数の return ステートメントがあり、if/else ステートメントもありますが、コンパイラーは return ステートメントから戻り値が int 型である必要があると推測できるため、末尾の戻り値の型は省略できます。
ただし、次の形式のように、コンパイラが戻り値の型を推論する際に矛盾が見つかったため、戻り値の型を明示的に指定する必要があります:
auto f10 = [](const int i) -> double {if(i % 5) return i * 5.0; else return i;}; transform(begin(test_data), end(test_data), begin(test_data), f10); for_each(begin(test_data), end(test_data), f6); cout<<endl;
概要
1.lambda 式の形式: [キャプチャ リスト] (パラメータ リスト) -> 戻り値の型 { 関数本体 }、パラメータ リストと戻り値の型は省略できます。
2. キャプチャ リストは値 [val] または参照 [&ref] をキャプチャできます。
3. キャプチャリストは暗黙的にローカル変数をキャプチャすることもできます。値 [=] をキャプチャする方法と参照 [&] をキャプチャする方法もあります。また、[&, val] をキャプチャすることもできます。 [=、&ref] を混合して使用します。
4. ラムダがキャプチャした値を変更する必要がある場合は、mutable キーワードを追加する必要があります。
4. lambda が戻り値の型を自動的に推論できない場合は、戻り値の型を追加して明示的に指定する必要があります。
以上がC++11の新機能であるラムダ式の内容です。この記事が皆様のC++学習の一助になれば幸いです。
C++11 の新機能を簡単に分析したラムダ式に関連するその他の記事については、PHP 中国語 Web サイトに注目してください。