ポインターの減衰と関数のオーバーロードの解決
C では、オーバーロードの解決は、指定された引数のセットに最も一致する関数を選択することを目的としています。複数の関数が実行可能な候補である場合、変換コストが最小の関数が優先されます。
文字配列の長さを出力する次の関数テンプレートを考慮します。
template <size_t N> void foo(const char (&s)[N]) { std::cout << "array, size=" << N - 1 << std::endl; }
foo( を呼び出すとき) "hello")、テンプレートの特殊化が正常に識別され、"array, size=5" が出力されます。ただし、非配列シナリオをサポートするために foo を拡張すると、あいまいさが生じます。
void foo(const char* s) { std::cout << "raw, size=" << strlen(s) << std::endl; }
さて、foo("hello") を呼び出すと、テンプレートの特殊化が特殊化されているように見えても、驚くべきことに "raw, size=5" が出力されます。
の理由あいまいさ
このあいまいさは、配列が本質的にその最初の要素へのポインタであり、配列からポインタへの変換が低コストになるために発生します。 C のオーバーロード解決ルールによれば、必要な変換操作が少ないオーバーロードが優先されます。この場合、配列からポインターへの変換は、必要なテンプレート引数の推論よりも上位にランクされる低コストの左辺値変換です。
曖昧さの回避
配列関数オーバーロードが確実に呼び出されるようにするには、次のように非配列オーバーロードを関数テンプレートとして定義することが回避策です。よく:
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; }
これにより、部分的な順序付けが開始されるため、テンプレートの特殊化が確実に優先されます。
以上がポインターの減衰が C 関数テンプレートのオーバーロード解決に影響するのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。