GCC は次のコードを受け入れます。
template <typename T>
struct meta
{
typedef typename T::type type;
};
struct S {};
template <typename T>
typename meta<T>::type foo(T, S);
int foo(int, int);
int main()
{
foo(0, 0);
}
しかし、clang は次のエラーで拒否します。
test.cpp:4:22: error: type 'int' cannot be used prior to '::' because it has no members
typedef typename T::type type;
^
test.cpp:10:10: note: in instantiation of template class 'meta<int>' requested here
typename meta<T>::type foo(T, S);
^
test.cpp:10:24: note: while substituting deduced template arguments into function template 'foo' [with T = int]
typename meta<T>::type foo(T, S);
^
これは、過負荷の解決中に GCC と clang が特定の操作を実行する順序の違いを示唆しているようです。テンプレート候補の戻り値の型をインスタンス化しようとする前にS
、GCC は 2 番目のパラメーター ( vs. int
)の型の不一致のためにテンプレート候補を破棄するようですが、clang はその逆を行うようです。
誰が正しいですか?
この質問は、テンプレート ライブラリの作成者にとって重要な意味を持つと思います。具体的には、clang が正しい場合、テンプレートの作成者はfoo
、エラーを置換の失敗に変えるために追加の作業を行う必要があります。
EDIT : 次のやや単純な例は、GCC と clang の両方で拒否され、同様のエラーが発生することに注意してください。
template <typename T>
struct meta
{
typedef typename T::type type;
};
template <typename T>
typename meta<T>::type foo(T);
int foo(int);
int main()
{
foo(0);
}
GCCは、「関数型とそのテンプレートパラメータ型の直接のコンテキストで無効な型と式のみが推論の失敗を引き起こす可能性がある」ことを知っていることを示唆しています. この例と元の例の違いは、元の例に 2 番目の関数パラメーターが存在することです。これに基づいて、GCC は戻り値の型で置換を実行しようとする前にテンプレート候補を破棄します。問題は、GCCがその順序で物事を行うのが正しいかどうか、または引数の型の一致を考慮する前に戻り値の型で置換を実行しようとする必要があるかどうかだと思います。
更新: Luc Danton の回答により、clang がコードを拒否するのは正しいと確信しました。それに応じて、GCC バグを提出しました。