web-dev-qa-db-ja.com

テンプレートへのこの呼び出しがあいまいにならないのはなぜですか?

2つのテンプレートを宣言します。1つ目は引数xをタイプTからタイプUに変換し、2つ目はタイプUからタイプTに変換します。 10でcastを呼び出すと、コンパイラは文句を言いません。どちらも使用する要件を満たしているので、あいまいさがあるはずですが、本当ですか?このコードは10を出力します。

#include <iostream>

template<typename T, typename U>
U cast(T x) {
    return static_cast<U>(x);
}

template<typename T, typename U>
T cast(U x) {
    return static_cast<T>(x);
}

int main() {
    std::cout << cast<int,float>(10) << '\n';
}
18
wic

cast<int, float>を使用すると、両方のテンプレートが考慮されます。

template<typename T=int,typename U=float>
U cast(T x);
template<typename T=int,typename U=float>
T cast(U x);

次に、次のように置き換えます。

template<typename T=int,typename U=float>
float cast(int x);
template<typename T=int,typename U=float>
int cast(float x);

現時点では、推測できるタイプはありません。そこで、過負荷の解決に進みます。

1つのケースでは、callingキャストのときにintを取得してfloatに変換でき、もう1つのケースではintを取得して変換します。 int when calling cast。キャストのbodyをまったく調べていないことに注意してください。ボディは過負荷の解決には関係ありません。

2番目の非変換(呼び出しの時点)はより適切に一致するため、過負荷が選択されます。

これを行った場合:

std::cout << cast<int>(10) << "\n";

物事はより面白くなります:

template<typename T=int,typename U=?>
U cast(T x);
template<typename T=int,typename U=?>
T cast(U x);

最初のものについては、Uを推測することはできません。 2つ目はできます。

template<typename T=int,typename U=?>
U cast(int x);
template<typename T=int,typename U=int>
int cast(int x);

したがって、ここでは実行可能なオーバーロードが1つあり、それが使用されます。

関数の引数が最初のテンプレートパラメータと完全に一致するため、インスタンス化はあいまいではありません。リテラル10intであり、これも最初のテンプレートタイプに明示的に指定されます。

引数の型が明示的に指定された型と一致しない場合(したがって、変換が必要)、インスタンス化をあいまいにすることができます。

// error: call of overloaded 'cast<int, float>(unsigned int)' is ambiguous
std::cout << cast<int,float>(10u) << "\n";
2
lubgr