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 выполняют определенные операции при разрешении перегрузки. GCC, похоже, выбрасывает кандидата шаблона из-за несоответствия типа во втором параметре (S
vs. int
), прежде чем пытаться создать экземпляр возвращаемого типа кандидата шаблона, в то время как 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 знает, что "только недействительные типы и выражения в непосредственном контексте типа функции и его типы параметров шаблона могут привести к отказу от вычета". Разница между этим примером и оригиналом заключается в наличии второго параметра функции в исходном примере, на основе которого GCC выбрасывает кандидата шаблона, прежде чем он даже попытается выполнить подстановку в возвращаемом типе. Я думаю, что вопрос заключается в том, правильно ли GCC делает что-то в этом порядке, или он должен попытаться выполнить подстановку типа возвращаемого значения, прежде чем рассматривать совпадения в типах аргументов.
ОБНОВЛЕНИЕ. Ответ Luc Danton убедил меня, что clang является правильным, чтобы отклонить код. Поэтому я подал ошибку GCC.