オーバーロード解決のあいまいさ: ポインタの減衰とテンプレートの推定
C では、オーバーロードされた関数が利用可能な場合、どの関数を呼び出すかを決定することができます。曖昧であること。そのようなケースの 1 つは、推定されたテンプレートよりもポインターの減衰が優先されることを含みます。
曖昧さの根
文字列の長さを出力する関数を考えてみましょう:
template <size_t N> void foo(const char (&s)[N]) { std::cout << "array, size=" << N - 1 << std::endl; } foo("hello") // prints array, size=5
非配列をサポートするには、追加のオーバーロードが必要です。追加:
void foo(const char* s) { std::cout << "raw, size=" << strlen(s) << std::endl; }
予期せず、最初のオーバーロードが呼び出されなくなりました:
foo("hello") // now prints raw, size=5
ポインター減衰とテンプレート推定
曖昧さこれは、配列が本質的にその最初の要素へのポインタであるために発生します。ポインター減衰は、配列を引数として渡すときに、配列をポインターに自動的に変換します。ただし、テンプレートの推定により、最初のオーバーロードと完全に一致します。
C 標準によれば、オーバーロード解決では、関数テンプレートの特殊化ではない関数が優先されます (特定の場合を除く)。この例では、配列からポインターへの変換は、テンプレート推定よりも優先度が低い左辺値変換です。
曖昧性の解消
曖昧さを解決する 1 つの方法は次のとおりです。 2 番目のオーバーロードも関数テンプレートとして定義し、部分的な順序付けを有効にします:
template <typename T> auto foo(T s) -> std::enable_if_t<std::is_convertible<T, char const*>{}> { std::cout << "raw, size=" << std::strlen(s) << std::endl; }
By型制約を指定すると、コンパイラは、最初のオーバーロードは配列に使用する必要があり、2 番目のオーバーロードは配列以外を処理する必要があると推測できます。
要約すると、ポインターの減衰は、配列の最初の要素にアクセスするためのショートカットを提供します。配列を使用すると、テンプレートが関係する場合、オーバーロードの解決に予期せぬあいまいさが生じる可能性があります。このような落とし穴を回避するには、関数のオーバーロードを注意深く検討し、型制約を慎重に使用することが重要です。
以上がポインタの減衰が C のオーバーロード解決におけるテンプレートの推定をオーバーライドするのはどのような場合ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。