+
式には+[](){}
単項である+
オペレータ。[expr.unary.op] / 7では次のように定義されています。
単項演算+
子のオペランドは、算術型、スコープなしの列挙型、またはポインタ型でなければならず、結果は引数の値です。
ラムダは算術型などではありませんが、変換できます。
[expr.prim.lambda] / 3
ラムダ式 [...] の型は、名前が付けられていない一意のunionクラス型(クロージャー型と呼ばれます)であり、そのプロパティについて以下で説明します。
[expr.prim.lambda] / 6
以下のための閉鎖型ラムダ式無有するラムダキャプチャ有するpublic
非virtual
以外explicit
const
の変換関数関数へのポインタを閉鎖型の関数呼び出し演算子と同じパラメータと戻り型を有します。この変換関数によって返される値は、呼び出されたときに、クロージャタイプの関数呼び出し演算子を呼び出すのと同じ効果を持つ関数のアドレスになります。
したがって、単項+
は、このラムダ用の関数ポインター型への変換を強制しますvoid (*)()
。したがって、式の型+[](){}
はこの関数ポインタ型void (*)()
です。
2番目のオーバーロードvoid foo(void (*f)())
は、オーバーロード解決のランキングで完全一致となり、したがって明確に選択されます(最初のオーバーロードは完全一致ではないため)。
ラムダ[](){}
はstd::function<void()>
、の非明示的なテンプレートctor を介してに変換できます。これstd::function
はCallable
、CopyConstructible
要件を満たすすべての型を取ります。
ラムダvoid (*)()
は、クロージャタイプの変換関数を介して(上記を参照)に変換することもできます。
どちらもユーザー定義の変換シーケンスであり、同じランクです。そのため、最初の例ではあいまいさのために過負荷の解決が失敗します。
DanielKrüglerの議論に裏打ちされたCassio Neriによると、この単項+
トリックは動作を指定する必要があります。つまり、これに依存することができます(コメントの説明を参照)。
それでも、あいまいさを避けたい場合は、関数ポインター型への明示的なキャストを使用することをお勧めします。SOに何が行われ、なぜ機能するのかを尋ねる必要はありません;)
std::bind
するstd::function
機能左辺値と同様に呼び出すことができるオブジェクト。