Функция шаблона перегружена одинаковыми сигнатурами, почему это работает?

Минимальная программа:

#include <stdio.h>

#include <type_traits>

template<typename S, typename T>
int foo(typename T::type s) {
    return 1;
}

template<typename S, typename T>
int foo(S s) {
    return 2;
}

int main(int argc, char* argv[]) {
    int x = 3;
    printf("%d\n", foo<int, std::enable_if<true, int>>(x));

    return 0;
}

выход:

    1 

Почему это не дает ошибку компиляции? Когда код шаблона сгенерирован, не будут ли функцииint foo(typename T::type search) а такжеint foo(S& search) есть такая же подпись?

Если вы немного измените сигнатуры функций шаблона, они все равно будут работать (как я и ожидал, учитывая приведенный выше пример):

template<typename S, typename T>
void foo(typename T::type s) {
    printf("a\n");
}

template<typename S, typename T>
void foo(S s) {
    printf("b\n");
}

Но это не так, и все же единственное отличие состоит в том, что один из них имеет сигнатуру int, а другой определяется первым параметром шаблона.

template<typename S, typename T>
void foo(typename T::type s) {
    printf("a\n");
}

template<typename S, typename T>
void foo(int s) {
    printf("b\n");
}

Ошибка компилятора (лязг):

test.cpp:26:2: error: call to 'foo' is ambiguous
foo<std::enable_if<true, int>>(3);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
test.cpp:16:6: note: candidate function [with T = std::__1::enable_if<true, int>]
void foo(typename T::type s) {
        ^
test.cpp:21:6: note: candidate function [with T = std::__1::enable_if<true, int>]
void foo(int s) {
        ^
1 error generated.

Я использую код, подобный этому, для проекта, над которым я работаю, и я боюсь, что есть тонкое в языке, которое я не понимаю, которое вызовет некоторое неопределенное поведение в определенных случаях. Я должен также упомянуть, что он компилируется как в Clang, так и в VS11, поэтому я не думаю, что это просто ошибка компилятора.

Редактировать: исправлено второе дело (опечатка); добавлено сообщение об ошибке от Clang.

Edit # 2: Для тех из вас, кто спросил, что означает T :: type.

Изhttp://en.cppreference.com/w/cpp/types/enable_if:

шаблон <bool B, класс T = void> struct enable_if;

Если B истинно, std :: enable_if имеет открытый тип typedef, равный T; в противном случае, нет члена typedef.

enable_if - это структура. По сути, если выражение, вычисленное в первом параметре шаблона enable_if, имеет значение true (а в случае с моими примерами выше это так), тогда будет открытый членtype имеет тот же тип, что и второй параметр шаблона.

На случай, еслиenable_if<true, int>, enable_if :: type имеет тип int.

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

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