5

非常に予期しないオーバーロード解決動作が発生しています。次のコードは、gcc と clang の両方によってあいまいなエラーで拒否されます。

template <typename T>
struct A
{
    typedef T key_type;
};

template <typename T>
void foo(A<T> rng, T val);

template <typename T, typename U = T>
void foo(T, typename U::key_type);

int main()
{
    A<int> i;
    foo(i, 0);
}

エラーは次のとおりです。

test.cpp:16:5: error: call to 'foo' is ambiguous
    foo(i, 0);
    ^~~
test.cpp:8:6: note: candidate function [with T = int]
void foo(A<T> rng, T val);
     ^
test.cpp:11:6: note: candidate function [with T = A<int>, U = A<int>]
void foo(T, typename U::key_type);
     ^

どちらも正確に一致すると予想されますが、最初のパラメーターA<T>ではT.

私が驚いたのは、2 番目の署名を次のように変更した場合です。

template <typename T, typename U = T>
void foo(T, typename T::key_type);

gcc と clang の両方がコードを受け入れるようになり、最初のオーバーロードを選択するようになりました。

この変更がどのように動作に違いをもたらすかわかりません。明示的に指定も推定もされていない ( U) テンプレート パラメーターの使用を、そのデフォルト値 ( T) に置き換えただけです。

繰り返しますが、変更前の動作はそもそも予期しないものであるため、何かが欠けている可能性があります。

誰かが説明できますか:

  1. 最初のケースがあいまいな理由。と
  2. なぜ私が行った変更が曖昧さを解決するのですか?

参考までに、私がテストしたコンパイラのバージョンは、gcc 4.8.0 と最近のトランク ビルドの clang です。

4

1 に答える 1

2

問題は、引数推定の後に、推定されたテンプレート引数のパラメーター リストへの置換フェーズがあるかどうかです。このフェーズでは、まだ推定されていないテンプレート パラメーターに対して既定の引数が使用されます。

この余分なステップが行われる演繹コンテキストと、そうでないものについての質問は、アクティブなコアの問題の対象です

その追加の置換ステップを実行する場合は、テンプレートもインスタンス化する必要があります (そうしないと、置換ステップ自体はあまり意味がありません)。置換を行わずにデフォルトの引数のみを選択することもできますが、標準ではこれら 2 つのことが一緒に行われるため、実装者として私はそのパスを選択しません。

部分的な順序付けは、部分的な順序付けが行われているコンテキストからはほとんど独立しています (コンテキストに依存するいくつかの事柄が考慮されます。たとえば、明示的な呼び出し引数を持たない関数パラメーターは無視されます)。また、テンプレート パラメーターに明示的なテンプレート引数が渡されたかどうかにも依存しません (そのため、 に値を指定した場合U、部分的な順序付けはそれを「記憶」していません。

Clang と GCC は置換ステップを実行せず、テンプレートのデフォルト引数を使用しません。したがって、Tを比較しU::key_typeて を理解するUと、彼らは「ああ、推論されていないコンテキストです。「成功、ミスマッチするものは何もない!」と言うでしょう。このパラメータについて」。Tと比較した場合も同様T::key_typeです。に沿って他の方向を比較すると、WhatEver::key_type依存TTも推測できます。したがって、2番目のパラメーターについては、両方の試行で、両方のテンプレートが少なくとも互いに特化しています。

ただし、重要な違いは、控除後、パラメータ タイプ リストで使用されるすべてのパラメータの値が存在する必要があることです。

ほとんどの場合、演繹が成功するためには、すべてのテンプレート パラメーターに値が必要ですが、部分的な順序付けの目的で、テンプレート パラメーターは、部分的な順序付けに使用される型で使用されていない限り、値を持たないままにすることができます。[ 注: 非推定コンテキストで使用されるテンプレート パラメータは、使用されていると見なされます。— エンドノート]

2回目の試行でTは、最初のパラメーターによって推測されたため、パラメーター/引数の型の比較が行われた後、悪いことは何も起こりませんでした. 最初の試行でUは、推定されないままであったため、最初のテンプレートは 2 番目のテンプレートよりも「より専門的」であるとは見なされませんでした。

于 2013-03-29T11:08:46.913 に答える