Разница в разрешающей способности при перегрузке между GCC и clang (SFINAE)

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 противint) before попытка создания экземпляра возвращаемого типа шаблона-кандидата, в то время как 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 знает, что «только недопустимые типы и выражения в непосредственном контексте типа функции и ее типов параметров шаблона могут привести к ошибке вывода». Разница между этим примером и оригиналом заключается в наличии второго параметра функции в исходном примере, на основе которого GCC выбрасывает кандидата-шаблона, прежде чем он даже попытается выполнить замену возвращаемого типа. Я думаю, что вопрос заключается в том, является ли GCC правильным, чтобы делать вещи в таком порядке, или он должен пытаться выполнить подстановку возвращаемого типа перед рассмотрением совпадений в типах аргументов.

UPDATEОтвет Люка Дантона убедил меня в том, что clang правильно отклоняет код. У меня соответственноподал ошибку GCC.

Ответы на вопрос(2)

Ваш ответ на вопрос