[解決済み] ラムダに対する関数ポインタとstd::functionの曖昧なオーバーロードを+で解決する(単項のプラス)
質問
次のコードでは、最初の呼び出しが
foo
の最初の呼び出しがあいまいであるため、コンパイルに失敗しています。
二つ目は、追加された
+
が追加されており、関数ポインタのオーバーロードに解決されます。
#include <functional>
void foo(std::function<void()> f) { f(); }
void foo(void (*f)()) { f(); }
int main ()
{
foo( [](){} ); // ambiguous
foo( +[](){} ); // not ambiguous (calls the function pointer overload)
}
は何ですか?
+
の表記は何をしているのでしょうか?
どのように解決するのですか?
この
+
という表現で
+[](){}
は単項
+
演算子です。で次のように定義されています。
[expr.unary.op]/7で定義されています。
単項演算子のオペランドは
+
演算子は算術型、スコープされていない列挙型、またはポインタ型でなければならず、結果は引数の値である。
ラムダは算術型等ではありませんが、変換することができます。
[expr.prim.lambda]/3
の型は ラムダ式 [は、ユニークで名前のない非ユニオンクラスの型であり、これは クロージャ型 - と呼ばれるもので、その特性は後述します。
[expr.prim.lambda]/6
<ブロッククオート
のクロージャ型は
ラムダ式
を持たない
ラムダ捕捉
は
public
以外の
virtual
非
explicit
const
への変換機能
関数へのポインタ
クロージャ型の関数呼び出し演算子と同じパラメタ及び戻り値の型をもつ関数へのポインタへの変換関数。この変換関数が返す値は,呼び出されたとき,クロージャ型の関数呼び出し演算子を呼び出すのと同じ効果をもつ関数のアドレスでなければならない。
したがって、単項の
+
は関数ポインタ型への変換を強制し、このラムダに対して
void (*)()
. したがって、式の型は
+[](){}
はこの関数ポインタ型
void (*)()
.
2つ目のオーバーロード
void foo(void (*f)())
はオーバーロードの解決のためのランキングで完全一致となり、したがって(最初のオーバーロードは完全一致ではないので)曖昧さなく選択されます。
ラムダは
[](){}
は、次のように変換されます。
std::function<void()>
の非明示的なテンプレートクラスターによって
std::function
を満たす任意の型を取ります。
Callable
と
CopyConstructible
の要件を満たしている必要があります。
ラムダはまた、次のように変換することができます。
void (*)()
の変換機能によって
クロージャ型
(の変換機能によって行われます(上記参照)。
どちらもユーザー定義の変換シーケンスで、同じランクのものです。そのため、オーバーロードの解決に失敗するのは 最初 の例では曖昧さのために過負荷の解決が失敗する理由です。
Cassio Neri によると、Daniel Krügler の議論に裏打ちされた、この単項式
+
トリックは指定された動作であるべきで、つまりあなたはそれに依存することができます (コメントでの議論を参照してください)。
それでも、曖昧さを回避したいのであれば、関数ポインタ型への明示的なキャストを使用することをお勧めします:SOで何をするのか、なぜそれが機能するのかを尋ねる必要はありません ;)
関連
-
[解決済み】C++ クラスヘッダが含まれているときに「不明な型」があるのはなぜですか?重複
-
[解決済み】C++ - 解放されるポインタが割り当てられていないエラー
-
[解決済み】C++ 式はポインタからオブジェクトへの型を持っている必要があります。
-
[解決済み] string does not name a type Errorが発生するのはなぜですか?
-
[解決済み】「corrupted size vs. prev_size」glibc エラーを理解する。
-
[解決済み】cc1plus:エラー:g++で認識されないコマンドラインオプション"-std=c++11"
-
[解決済み] 式はクラス型を持つ必要があります。
-
[解決済み】1つ以上の多重定義されたシンボルが見つかる
-
[解決済み】警告 - 符号付き整数式と符号なし整数式の比較
-
[解決済み】キャプチャしたラムダを関数ポインタとして渡す
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】C++ クラスヘッダが含まれているときに「不明な型」があるのはなぜですか?重複
-
[解決済み】IntelliSense:オブジェクトに、メンバー関数と互換性のない型修飾子がある
-
[解決済み】C++の変数はイニシャライザーを持っているが、不完全な型?
-
[解決済み】エラー:strcpyがこのスコープで宣言されていない
-
[解決済み】C++プログラムでのコンソールの一時停止
-
[解決済み] 警告:暗黙の定数変換でのオーバーフロー
-
[解決済み] 変数サイズのオブジェクトが初期化されないことがある c++
-
[解決済み】エラー。引数リストに一致するコンストラクタのインスタンスがない
-
[解決済み】c++で.txtファイルから2次元の配列に読み込む
-
[解決済み】 正のラムダ:'+[]{}' - これは何の妖術か?[重複している]