C ++ラムダコンパイラの実装原理

ラムダ式の構文

次のように完全な形式ラムダ式は以下のとおりです。

[捕获列表] (形参列表) mutable 异常列表-> 返回类型
{
    函数体
}

様々な意味:

  1. キャプチャリスト:変数キャプチャ外部変数は、関数が外部変数をトラップされていない、すなわち、省略することができる体を捕獲するために使用することができます。
  2. パラメータリスト:パラメータリストと同じの正常な機能。これは、すなわち、いかなるパラメータリストを省略することはできません
  3. 可変:可変キーワードがあれば、あなたはどうかオミット、特定のニーズに決定し、関数本体で撮影した変数を変更することができます。
  4. 例外の一覧:noexcept /スロー(...)、および例外のリストは、通常の関数のように、その代表者は、例外の任意の型を投げることがあり、省略することができます。
  5. 戻り値の型:戻り値の型と同じ機能。これを省略することができ、および省略された場合、コンパイラが自動的に戻り値の型が派生します。
  6. 関数本体:コード。それは省略しますが、無意味にすることができます。

使用例

void LambdaDemo()
{
    int a = 1;
    int b = 2;
    auto lambda = [a, b](int x, int y)mutable throw() -> bool
    {
        return a + b > x + y;
    };
    bool ret = lambda(3, 4);
}

コンパイラの実装の原則

コンパイラの実装ラムダ式は広くどのような手順に分かれています

  1. 作成ラムダクラスを、コンストラクタを実装し、ラムダ式関数の重量負荷使用してオペレータ() また、匿名関数オブジェクトので、ラムダ式と呼ばれる)を
  2. ラムダオブジェクトを作成します。
  3. オブジェクトを介してコール演算子()

コンパイラの意志のラムダ式変換されたコード:

class lambda_xxxx
{
private:
    int a;
    int b;
public:
    lambda_xxxx(int _a, int _b) :a(_a), b(_b)
    {
    }
    bool operator()(int x, int y) throw()
    {
        return a + b > x + y;
    }
};
void LambdaDemo()
{
    int a = 1;
    int b = 2;
    lambda_xxxx lambda = lambda_xxxx(a, b);
    bool ret = lambda.operator()(3, 4);
}

その中でも、クラス名lambda_xxxx XXXXのは、名前の重複を加えないようにすることです。

lambda_xxxxとラムダ式の間の対応

  1. ラムダ式をキャプチャリスト、対応するlambda_xxxxクラスのプライベートメンバー
  2. ラムダ式のパラメータリスト lambda_xxxxクラスのメンバ関数に対応するオペレータを()パラメータリストで
  3. ラムダ式可変に対応し、lambda_xxxxクラスメンバ関数演算子()constは、一定の特性があるかどうか、すなわち、多くの場合、メンバ関数
  4. ラムダ式の戻り型、対応lambda_xxxxクラスのメンバー関数演算子()戻り型
  5. ラムダ式の機能体、lambda_xxxxクラスメンバ関数に対応する演算子()メンバ関数

さらに、ラムダ式捕捉、捕捉リストは、また、クラスlambda_xxxxのプライベートメンバーに対応するタイプに影響を与えます

  1. 値のキャプチャ:キャプチャのタイプのプライベートメンバ変数の同じタイプ
  2. キャプチャ参照:参照型のプライベートメンバ変数の型がキャプチャされます

任意の外部変数をキャプチャしないでください。

ラムダ式は、任意の外部変数をキャプチャしていない場合は、特定の状況下で、追加のコード生成があるでしょう。
前記特定のケースの手段:そこlambda_xxxxクラスへの関数ポインタ型変換
、次のコードと

typedef int(_stdcall *Func)(int);
int Test(Func func)
{
	return func(1);
}
void LambdaDemo()
{
	Test([](int i) {
		return i;
	});
}

テスト関数は、引数として関数ポインタをとり、関数ポインタを呼び出します。

試験は、実際の呼び出しは、それがラムダ式渡されたパラメータがある場合、したがって暗黙的な変換の一種である
機能にlambda_xxxx =>ポインタ。

既に述べたように、ラムダ式は、通常lambda_xxxx匿名オブジェクトクラス、関数ポインタが、上記のコードは、問題がないとの間で変換するために存在するべきではないれています。

それはですが、キーは彼らの言うことです式は任意の外部変数、すなわちlambda_xxxxクラスは何のメンバ変数、演算子を(持っていない)を捕捉しないラムダは、任意のメンバ変数で使用されることはありません問題、上記のコード、、、演算子()でありますメンバ関数は、この呼び出しに頼ることはできません。

彼らはこれに依存しないので、その関数ポインタ匿名lambda_xxxxオブジェクトクラス間の遷移があるかもしれません。

実質的に、次のとおりです。

  1. lambda_xxxxのクラス生成静的機能、静的関数シグネチャの関数と演算子()と一致することによって、この静的関数では、ヌルポインタ呼び出し演算子のクラス()に
    2オーバーロードlambda_xxxx型変換関数ポインタオペレータは、この機能では、リターンアドレスの静的関数の最初のステップ。

翻訳コンパイラの後のコード次のコード:

typedef int(_stdcall *Func)(int);

class lambda_xxxx 
{
private:
	//没有捕获任何外部变量,所有没有成员
public:
        /*...省略其他代码...*/
	int operator()(int i)
	{
		return i;
	}
	static int _stdcall lambda_invoker_stdcall(int i)
	{
		return ((lambda_xxxx *)nullptr)->operator()(i);
	}

	operator Func() const
	{
		return &lambda_invoker_stdcall;
	}
};

int Test(Func func)
{
	return func(1);
}
void LambdaDemo()
{
	auto lambda = lambda_xxxx ();
	Func func = lambda.operator Func();
	Test(func);
}

上記のコードでは単に__stdcall規則関数ポインタ例を呼び出す、実際の使用の異なる呼び出し規約は、静的な型変換関数と関数の対応するバージョンを生成します

これらの結論の正しさの明示的な呼び出し変換機能を発揮し、分解ラムダのために

void LambdaDemo()
{
	auto lambda = [](int i) {return i;};
	Func func = lambda.operator Func();
	Test(func);
}
  • 関数ポインタに変換

1png

738 X 691221 X 114

  • 戻り値の型として静的関数lambda_invoker_stdcallアドレス変換機能

2png

  • この呼び出し演算子として0を使用して、静的関数lambda_invoker_stdcall()

3png

おすすめ

転載: www.cnblogs.com/cute/p/12455769.html