IMHO GCC は間違っていて、CLANG は正しいと思います。以下で私の主張を正当化しようとします。
標準§14.8.3/p1によると、過負荷の解決 [temp.over] ( Emphasis Mine ) :
関数テンプレートは、その名前の (非テンプレート) 関数または同じ名前の (他の) 関数テンプレートのいずれかによってオーバーロードできます。その名前への呼び出しが (明示的に、または演算子表記を使用して暗黙的に) 書き込まれると、テンプレート引数推定 (14.8.2) と明示的なテンプレート引数のチェック (14.3) が関数テンプレートごとに実行され、その関数テンプレートで使用できるテンプレート引数値 (存在する場合) を見つけて、関数テンプレートの特殊化をインスタンス化できます。呼び出し引数で呼び出されます。関数テンプレートごとに、引数の推定とチェックが成功した場合、テンプレート引数 (推定および/または明示的) を使用して、オーバーロード解決で使用される候補関数セットに追加される単一の関数テンプレートの特殊化の宣言を合成します。 .特定の関数テンプレートについて、引数推定が失敗するか、合成された関数テンプレートの特殊化が不適切な形式である場合、そのような関数はそのテンプレートの候補関数のセットに追加されません。候補関数の完全なセットには、すべての合成された宣言と、同じ名前の非テンプレート オーバーロード関数がすべて含まれています。合成された宣言は、13.3.3 で明示的に説明されている場合を除き、オーバーロード解決の残りの部分で他の関数と同様に扱われます。144
[例:
template<class T> T max(T a, T b) { return a>b?a:b; }
void f(int a, int b, char c, char d) {
int m1 = max(a,b); // max(int a, int b)
char m2 = max(c,d); // max(char a, char b)
int m3 = max(a,c); // error: cannot generate max(int,char)
}
144) 関数テンプレートの特殊化のパラメーターには、テンプレート パラメーターの型が含まれていません。推定された引数で許可される変換のセットは制限されます。これは、引数推定プロセスが呼び出し引数と完全に一致するか、許可された制限された変換によってブリッジできる方法のみが異なるパラメーターを持つ関数テンプレートを生成するためです。推定されていない引数は、変換の全範囲を許可します。13.3.3 では、テンプレートの特殊化よりも非テンプレート関数が優先されることを指定していることにも注意してください。
上記から、明示的なテンプレート引数がチェックされ、チェックが成功した場合は、オーバーロード解決のために候補関数に追加される特殊化を合成するために使用されることがわかります。したがって、明示的に指定したという事実はX
、プロセスには関係ありません。
また、C++ 標準§13.3.3/p1.7 から Best viable function [over.match.best] :
F1
およびF2
は関数テンプレートの特殊化であり、
14.5.6.2 で説明されている半順序規則に従って、関数テンプレートF1
は のテンプレートよりも特殊化されています。F2
§14.5.6.2/p3から、関数テンプレートの部分的な順序付け [temp.func.order]部分的な順序付けでは、パラメーター パックも有効になるため、ここでも問題ありません。
今:
template <typename X, typename... T>
auto bar(int, T...) -> void;
次のものよりも専門的です。
template <typename X, typename Check, typename... T>
auto bar(Check, T...) -> void;
したがって、次のように呼び出します。
bar<void>(7, "");
曖昧ではありません。
上記に基づいて、これは GCC のバグだと思います。