VC++ 2012 では、"ステートレス ラムダを関数ポインターに" 変換するときに、コンパイラはステートレス ラムダ (キャプチャ変数を持たない) の変換を自動的に呼び出すことを選択します。
MSDN C++11 の機能:
ラムダス
[...] さらに、Visual Studio 2012 の Visual C++ では、ステートレス ラムダを関数ポインターに変換できます。[...] (Visual Studio 2012 の Visual C++ はそれよりもさらに優れています。これは、ステートレス ラムダを、任意の呼び出し規則を持つ関数ポインターに変換できるようにしたためです。これは、__stdcall
関数ポインターのようなものを期待する API を使用している場合に重要です。 .)
編集:
注意:呼び出し変換は C++ 標準外です。プラットフォーム ABI (アプリケーション バイナリ インターフェイス) などの他の仕様に依存します。
次の回答は、 /FAs コンパイラ オプションを使用した出力アセンブリ コードに基づいています。単なる推測ですので、詳細については Microsoft にお問い合わせください ;P
Q1. C++ ラムダ関数の呼び出し規約は何ですか?
Q3. 呼び出し規約が定義されていない場合、ラムダ関数を呼び出した後にスタックスペースを正しくリサイクルする方法は?
まず、C++ lambda(-expression)は関数 (または関数ポインター) ではありませんoperator()
。通常の関数の呼び出しのようにラムダ オブジェクトを呼び出すことができます。また、出力アセンブリ コードは、VC++ 2012 が__thiscall
変換を呼び出してラムダ ボディを生成することを示しています。
Q2. C++ ラムダ関数の呼び出し規約を指定するには?
私の知る限り、方法はありません。(のみの場合もあります__thiscall
)
Q4. コンパイラはラムダ関数の複数のバージョンを自動的に生成しますか? すなわち、次の疑似コードとして: [...]
おそらくいいえ。VC++ 2012 ラムダ型は、1 つのラムダ本体実装 ( void operator()()
) のみを提供しますが、変換の呼び出しごとに複数の「関数ポインターへのユーザー定義の変換」を提供します (演算子は、、、および型の関数ポインターを返しvoid (__fastcall*)(void)
ますvoid (__stdcall*)(void)
) void (__cdecl*)(void)
。
以下に例を示します。
// input source code
auto lm = [](){ /*lambda-body*/ };
// reversed C++ code from VC++2012 output assembly code
class lambda_UNIQUE_HASH {
void __thiscall operator()() {
/* lambda-body */
}
// user-defined conversions
typedef void (__fastcall * fp_fastcall_t)();
typedef void (__stdcall * fp_stdcall_t)();
typedef void (__cdecl * fp_cdecl_t)();
operator fp_fastcall_t() { ... }
operator fp_stdcall_t() { ... }
operator fp_cdecl_t() { ... }
};
lambda_UNIQUE_HASH lm;