ラムダ式
ラムダ式の形式
C ++ 11のラムダ式は、プログラミングを簡素化するために無名関数オブジェクトを定義および作成するために使用されます。
Lambdaの構文は次のとおりです。
[函数对象参数] (操作符重载函数参数) mutable 或 exception 声明 -> 返回值类型 {函数体}
コード形式:
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
using fptr = int(*)(int& obj);
int main()
{
fptr fobj = [](int& obj)mutable throw(int)->int {return obj; };
}
ご覧のとおり、Lambdaは主に[関数オブジェクトパラメーター]、(演算子オーバーロード関数パラメーター)、可変または例外宣言、->戻り値タイプ、{関数本体}の5つの部分に分かれています。
キャプチャリスト:[キャプチャパラメータリスト]
ラムダ式の開始を識別します。この部分は存在する必要があり、省略できません。関数オブジェクトのパラメーターは、コンパイラーによって自動的に生成された関数オブジェクトクラスのコンストラクターに渡されます。関数オブジェクトパラメーターは、ラムダが定義されるまで(ラムダが配置されているクラスのこれを含む)、ラムダのスコープに表示されるローカル変数のみを使用できます。関数オブジェクトパラメータの形式は次のとおりです。
①空:外部パラメータをキャプチャしません。キャプチャは実際には「スコープ内の変数は関数本体で直接使用されます」です。
②=:関数本体はLambdaのスコープ内のすべての可視ローカル変数(Lambdaが配置されているクラスのこれを含む)を使用でき、値転送メソッドです(コンパイラーがすべてのローカル変数を値で自動的に渡すのと同じです) );
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
int main()
{
int a = 10;
vector<int> obj{ 1,2,3,4,5 };
for_each(obj.begin(), obj.end(), [=](int& obj)mutable {obj += a; cout << obj << endl; });
}
変数を値で渡します:
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
int main()
{
int a = 10;
vector<int> obj{ 1,2,3,4,5 };
for_each(obj.begin(), obj.end(), [a](int& obj)mutable {obj += a; cout << obj << endl; });
}
注意:
Mutableの機能は、ラムダ関数本体内のキャプチャリストによってキャプチャされた変数の値を変更することですが、値の転送によってパラメーターを渡すため、ラムダ関数本体の内部を変更しても外部aは変更されません。
③&:関数本体は、Lambdaのスコープ内で表示されるすべてのローカル変数(Lambdaが配置されているクラスのこれを含む)を使用でき、参照によって渡されます(コンパイラーがすべてのローカル変数を参照によって自動的に渡すのと同じです) ;
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
int main()
{
int a = 10;
vector<int> obj{ 1,2,3,4,5 };
for_each(obj.begin(), obj.end(), [&](int& obj)mutable {obj += a; cout << obj << endl; });
}
参照によって単一の変数をキャプチャするには:
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
int main()
{
int a = 10;
vector<int> obj{ 1,2,3,4,5 };
for_each(obj.begin(), obj.end(), [&a](int& obj)mutable {obj += a; cout << obj << endl; });
}
④this:Lambdaが配置されているクラスのメンバー変数を関数本体で使用できます。
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
#include <string>
#include <functional>
class Person
{
public:
int age;
string name;
public:
Person(int age, string name)
{
this->age = age;
this->name = name;
}
void ShowInf()
{
function<void()> fptr = [this]() {cout << this->name << "的年龄为" << this->age << endl; };
fptr(); // 调用lambda函数
}
};
int main()
{
Person obj(12, "张三");
obj.ShowInf();
}
注意:
⑴ここでのラムダ式のプロトタイプはfunction <return data type(parameter data type)>であり、C言語の関数ポインターに似ています。実際、2つは基本的に同じですが、ラムダ式にはさらに「 「リスト」のみをキャプチャします。
⑵覚えておいてください:このポインタを渡すので、静的メンバーをクラスで呼び出すことはできません!
次のコードは正しいですか:
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
#include <string>
#include <functional>
class Person
{
public:
int age;
string name;
static int mark;
public:
Person(int age, string name)
{
this->age = age;
this->name = name;
}
function<void()> ShowInf()
{
return [this]() {cout << this->name << "的年龄为" << this->age << endl; }; // 返回lambda表达式
}
};
int main()
{
Person obj(12, "张三");
obj.ShowInf();
}
これは間違っています。なぜそれが間違っているのか調べてみましょう。
上記のコードでラムダ式によって返されるデータ型は無効であるため、ラムダ式を返す結果も無効です。
Lambda関数の新しい使用法:
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
#include <string>
#include <functional>
class Person
{
public:
int age;
string name;
static int mark;
public:
Person(int age, string name)
{
this->age = age;
this->name = name;
}
void ShowInf()
{
function<void()> fptr = [this]() {cout << this->name << "的年龄为" << this->age << endl; };
fptr(); // 调用lambda函数
}
};
int main()
{
Person obj(12, "张三");
obj.ShowInf();
int fptr1 = [&](int obj) {cout << obj << endl; return 0; }(4); // fptr1的数据类型是int整型
cout << typeid(fptr1).name() << endl;
}
上記のコードを見てください。次のコードが最も重要です。
int fptr1 = [&](int obj) {cout << obj << endl; return 0; }(4); // fptr1的数据类型是int整型
fptrはint型ですが、これはなぜですか?
function<int(int)> fptr1 = [&](int obj) {cout << obj << endl; return 0; };
fptr1(4);
同等のコードが上に示されています。実際、ラムダ式の最後の括弧はパラメーターを渡すために使用されます。
ただし、これには前提条件があります。ラムダ式によって返されるデータ型をvoidにすることはできません。voidデータ型の場合、この形式は使用できません。つまり、void型データを受け取る変数がありません。
戻り値のデータ型がvoidであるラムダ式の形式は次のとおりです。
[&](int obj) {cout << obj << endl; }(9);
⑤a、&b:aを値で渡し、bを参照で渡します。
⑥=、&a、&b。aとbが参照によって渡されることを除いて、他のパラメーターは値によって渡されます。
△&、a、b。値によって渡されるaとbを除いて、他のパラメーターは参照によって渡されます。
データ型を宣言する必要のない変数は、キャプチャリストで定義し、ラムダ関数の本体で使用できます。
パラメータリスト:(機能パラメータリスト)
オーバーロードされた()演算子のパラメーターを識別します。パラメーターがない場合は、この部分を省略できます。パラメータは、値(:(a、b)など)および参照(:(&a、&b)など)で渡すことができます。
可変または例外ステートメント
この部分は省略できます。関数オブジェクトのパラメーターを値で渡す場合、可変修飾子を追加した後、渡されたコピーを変更できます(値自体ではなく、コピーを変更できることに注意してください)。例外宣言は、整数型の例外のスローなど、関数によってスローされる例外を指定するために使用されます。throw(int)を使用できます。
->戻り値のタイプ
関数の戻り値の型を識別します。戻り値が無効である場合、または関数本体に戻り値が1つしかない場合(コンパイラーはこの時点で戻り値の型を自動的に推測できます)、この部分は省略できます。
{機能本体}
関数の実現を識別します。この部分は省略できませんが、関数本体は空にすることができます。
匿名関数をインスタンス化する
匿名関数を変数、配列、またはベクトルに格納し、名前付きパラメーターとして渡します。
#include <iostream>
using namespace std;
#include <functional>
#include <vector>
int main()
{
function<void(int, int)> fptr = [](int obj1, int obj2) {cout << obj1 + obj2 << endl; }; // 必须参数类型一一对应
fptr(1, 1);
vector<function<void(int, int)>> obj{ fptr };
obj[0](1, 2);
function<void(int, int)> fptr_array[1]{ fptr };
fptr_array[0](4, 6);
}
ラムダ無名関数と関数ポインターの相互変換
#include <iostream>
using namespace std;
#include <functional>
using f_ptr = void(*)(int, int);
int main()
{
function<void(int, int)> fptr = [](int obj1, int obj2) {cout << obj1 + obj2 << endl; };
f_ptr fptr1 = [](int obj1, int obj2) {cout << obj1 + obj2 << endl; };
//f_ptr = fptr; // 不存在function<void(int,int)>对象转化至void(*)(int, int)对象
fptr1(1, 3);
}
注:ラムダ式は関数ポインターよりも高度であるため、つまり「外部データをキャプチャする」という追加機能があります。したがって、対応するタイプの関数ポインターにラムダ式を割り当てる場合、キャプチャリスト[]はairである必要があります。 !