曖昧さの理解: std::function の署名は不変ですか?
C の領域では、 std::function テンプレートは一般的に呼び出し可能なオブジェクトと関数ポインターをカプセル化するために使用されます。ただし、このテンプレートをさまざまなシグネチャの関数とともに使用すると、独特のあいまいさが生じます。この困惑の背後にある根本的な理由を掘り下げてみましょう。
曖昧さの根源
問題の核心は、std::function のシグネチャの一見変更可能な性質にあります。次のコード スニペットを考えてみましょう。
<code class="cpp">int a(const std::function<int()>& f) { return f(); } int a(const std::function<int(int)>& f) { return f(0); }</code>
直感的に、a(x) または a(y) を呼び出すとき、x は引数を取らない関数、y は 1 つの引数を取る関数であり、明確な解決が期待されます。適切な関数オーバーロードに設定します。ただし、コンパイラはジレンマに遭遇します。
<code class="cpp">a(x); // Ambiguous a(y); // Ambiguous</code>
このパズルは、std::function
型消去、犯人
この現象を理解するために、型消去の概念を導入します。これは、任意の関数とオブジェクトのカプセル化を可能にするために std::/boost::function で使用される手法です。これにより柔軟性が得られますが、あいまいな変換が行われる可能性があります。
コンパイラーは、オーバーロードされたセットに適した関数を特定しようとする際、関数パラメーターのコンストラクターまたは引数の変換を使用して、指定された引数を変換しようとします。オペレーター。私たちの場合、関数パラメーターのコンストラクター (std::function) は事実上何でも受け入れるため、変換試行中にあいまいさが生じます。
それでは、署名は変更可能ですか?
結論として、std::function のシグネチャは、宣言と定義中にその型を定義する役割を果たします。ただし、初期化プロセスは制御されず、その結果、一見変更可能なシグネチャが観察されるという興味深い結果が得られます。
曖昧さの回避策
曖昧さを回避するには、次の方法があります。明示的なキャストに頼る:
<code class="cpp">a((std::function<int()>)(x)); a((std::function<int(int)>)(y));</code>
あるいは、関数オブジェクトを使用するか、テンプレート メタプログラミング (TMP) を利用して、明示的なキャストの必要性を排除することもできます。 TMP は冗長なソリューションを提供しますが、キャスト操作をクライアントから隠します。
全体として、型消去メカニズムと、std::function での宣言時と初期化時の型の区別を理解することは、そのような曖昧さを防ぐために重要です。シナリオ。
以上がstd::function の署名は初期化後に変更できますか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。