Stack Overflowの質問C++11 ではラムダの再定義は許可されていません。なぜでしょうか?コンパイルされない小さなプログラムが与えられました:
int main() {
auto test = []{};
test = []{};
}
質問は答えられ、すべてうまくいったように見えました。そしてヨハネス・シャウブそして作った興味深い観察:
+
最初のラムダの前にを置くと、魔法のように動作し始めます。
そこで疑問に思うのですが、なぜ次の方法が機能するのでしょうか?
int main() {
auto test = +[]{}; // Note the unary operator + before the lambda
test = []{};
}
ベストアンサー1
はい、コードは標準に準拠しています。+
ラムダの単純な古い関数ポインターへの変換がトリガーされます。
何が起こるかというと:
コンパイラは最初のラムダ ( []{}
) を見て、§5.1.2 に従ってクロージャ オブジェクトを生成します。ラムダは非キャプチャラムダなので、次のようになります。
5.1.2 ラムダ式 [expr.prim.lambda]
6ラムダキャプチャのないラムダ式のクロージャ型には、クロージャ型の関数呼び出し演算子と同じパラメータと戻り値の型を持つ関数へのポインタへの、パブリックな非仮想非明示的 const 変換関数があります。この変換関数によって返される値は、呼び出されると、クロージャ型の関数呼び出し演算子を呼び出すのと同じ効果を持つ関数のアドレスになります。
単項演算子には+
組み込みオーバーロードのセットがあり、具体的には次のものがあるため、これは重要です。
13.6 組み込み演算子 [over.built]
8あらゆる型に対して、
T
次のような候補演算子関数が存在する。
T* operator+(T*);
これにより、何が起こるかが非常に明確になります。演算子が+
クロージャ オブジェクトに適用されると、オーバーロードされた組み込み候補のセットに任意のポインタへの変換が含まれ、クロージャ タイプにはラムダの関数ポインタへの変換という 1 つの候補だけが含まれます。
test
したがって、のの型auto test = +[]{};
は と推論されますvoid(*)()
。これで 2 行目は簡単になります。2 番目のラムダ/クロージャ オブジェクトの場合、関数ポインタへの割り当てによって、1 行目と同じ変換がトリガーされます。2 番目のラムダのクロージャ型は異なりますが、結果の関数ポインタはもちろん互換性があり、割り当てることができます。