c++におけるlambda式の使い方

4871 ワード

  • 基礎用法
  • 2 2点注意


  • 1.基本的な使い方
    c++11は匿名関数のサポートを提供し、Lambda関数(Lambda式とも呼ばれる)と呼ばれます.Lambda式は関数をオブジェクトと見なします.Lambda式は、変数やパラメータとして渡すなど、オブジェクトのように使用できます.関数のように評価することもできます.Lambda式は本質的に関数宣言とよく似ています.Lambda式の具体的な形式は、[capture](parameters)です.mutable->return-type{} 1.[capture]:リストをキャプチャし、常にLambda関数の開始に表示されます.実際には[]はLambda引数です.コンパイラは、この引数に基づいて、次のコードがLambda関数であるかどうかを判断します.スナップリストは、Lambda関数で使用するためにコンテキスト内の変数をスナップできます.2.(parameters):パラメータリスト.通常の関数のパラメータリストと一致します.パラメータ伝達が不要な場合は、カッコ「()」とともに省略できます.
    3.mutable:mutable修飾子.デフォルトでは、Lambda関数は常にconst関数であり、mutableは定数を取り消すことができます.この修飾子を使用する場合、パラメータリストは省略できません(パラメータが空であっても).
    4->return-type:戻りタイプ.関数の戻りタイプをトレース戻りタイプとして宣言します.戻り値を必要としない場合には、記号"->"とともに省略することもできます.また、戻りタイプが明確な場合は、この部分を省略して、コンパイラに戻りタイプを導出させるようにしてもよい.
    5.{statement}:関数体.内容は通常の関数と同じですが、パラメータのほかに、取得したすべての変数を使用できます.
    通常の関数との最大の違いは、パラメータの使用に加えて、Lambda関数がキャプチャリストを使用してコンテキスト内のデータにアクセスできることです.具体的には、スナップリストには、コンテキスト内でLambdaで使用できるデータと、値で渡す方法または参照で渡す方法が記載されています.構文的には、[]にはスナップリストが含まれており、スナップリストは複数のスナップ項目で構成され、カンマで区切られています.スナップリストには、次のような形式があります.
    1.[var]は値伝達方式が変数varを捕捉することを表す.2.[=]は値伝達方式がすべての親作用域を捕捉する変数(thisを含む)を表し、3.[&var]は参照伝達捕捉変数varを表し、4.[&]は参照伝達方式がすべての親作用域を捕捉する変数(thisを含む)を表し、5.[this]は値伝達方式が現在のthis針を捕捉することを表す.
    親ドメイン、すなわちLambda関数を含む文ブロックについて述べたが、一般的にはLambdaを含む「{}」コードブロックである.上のスナップリストは、次のように組み合わせることもできます.
    1.[=,&a,&b]は、伝達を参照して変数aおよびbを捕捉し、他のすべての変数を値伝達で捕捉することを表す.2.[&,a,this]は、変数aとthisを値伝達で捉え、伝達方式を参照して他のすべての変数を捕捉することを表す.
    ただし、スナップリストでは変数の繰返しは許可されていません.次の例は典型的な繰り返しであり、コンパイル時期のエラーを引き起こす.例:
    3.[=,a]ここではすべての変数を値伝達でスナップしたが、aを繰り返しスナップすると、エラーが報告される.4.[&,&this]ここで&はすべての変数を参照伝達でスナップし、thisをスナップするのも繰り返しです.
    2.注意点
    例1:
    #include 
    using namespace std;
    
    int main(){
        int a = 10;
        auto func1 = [=]{return a + 1;};
        auto func2 = [&]{return a + 1;};
        cout << func1() << endl;
        cout << func2() << endl;
        a++;
        cout << func1() << endl;
        cout << func2() << endl;
        return 0;
    }
    

    出力結果:
    11
    11
    11
    12

    なぜ3番目の結果は11で、4番目の結果は12なのでしょうか.これはfunc 1式ではaが定数として扱われ、一度初期化されても変化しないため、式ではaと同名のconst変数がcopyされていると考えられ、func 2式ではaは親ドメインの値を使用しているため、lambda関数を使用する場合、キャプチャする値がLambda関数の定数となる場合、私たちは通常、値によって渡される方法でスナップします.逆に、スナップする必要がある値がLambda関数の実行時の変数になっている場合は、参照でスナップする必要があります.例2:
    #include 
    using namespace std;
    
    int main(){
        int a = 10;
        cout << [=]{return ++a;}() << endl;
        cout << [&]{return ++a;}() << endl;
        return 0;
    }

    コンパイルは間違って、aは読み取り専用だと言って、次のコードに変えればいいです.
    #include 
    using namespace std;
    
    int main(){
        int a = 10;
        cout << [=]()mutable{return ++a;}() << endl;
        cout << [&]{return ++a;}() << endl;
        return 0;
    }

    これは、デフォルトではLambda関数は常にconst関数であり、mutableは定数を取り消すことができるためです.規定に従って、1つのconstのメンバー関数は、関数内で非静的メンバー変数を変更できない値である.
    まとめ:スナップというブロックは、値で渡すと、式の定義の瞬間に式の内部に変数がcopyされ、値は永遠に変わらない.式が複数の場所で呼び出されても、外部変数の変化は内部に影響しない.式の内部で変数の値を変えるにはmutableキーワードを追加する必要がある.参照によって伝達される場合、式で使用される値は外部の変数の値であり、外部の変数の値が変化すると、式の内部で得られる値も変化し、式の内部でもその変数を変更することができ、mutableキーワードを追加する必要はありません.