Przeładowanie funkcji szablonu identycznymi podpisami, dlaczego to działa?

Minimalny program:

#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;
}

wydajność:

    1 

Dlaczego nie daje to błędu kompilacji? Gdy wygenerowany zostanie kod szablonu, nie będzie funkcjiint foo(typename T::type search) iint foo(S& search) masz ten sam podpis?

Jeśli nieco zmienisz sygnatury funkcji szablonu, to nadal działa (jak można by się spodziewać po powyższym przykładzie):

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");
}

Ale to nie jest, a jedyną różnicą jest to, że jeden ma podpis int, a drugi jest zdefiniowany przez pierwszy parametr szablonu.

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");
}

Błąd kompilatora (Clang):

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.

Używam kodu podobnego do tego dla projektu, nad którym pracuję, i obawiam się, że istnieje subtelnie język, którego nie rozumiem, który spowoduje pewne niezdefiniowane zachowanie w niektórych przypadkach. Powinienem również wspomnieć, że kompiluje się zarówno w Clang, jak iw VS11, więc nie sądzę, aby był to tylko błąd kompilatora.

Edytuj: poprawiono drugi przypadek (literówka); dodano komunikat o błędzie od Clang.

Edytuj # 2: Dla tych, którzy pytali, co oznacza typ T ::.

Zhttp://en.cppreference.com/w/cpp/types/enable_if:

szablon <bool B, klasa T = void> struct enable_if;

Jeśli B jest prawdziwe, std :: enable_if ma typ typef publicznego członka, równy T; w przeciwnym razie nie ma typedef członka.

enable_if jest strukturą. Zasadniczo, jeśli wyrażenie obliczone w pierwszym parametrze szablonu enable_if jest prawdziwe (aw przypadku moich przykładów powyżej, to jest), wtedy będzie członek publicznytype który ma ten sam typ co drugi parametr szablonu.

W przypadkuenable_if<true, int>, enable_if :: type ma typ int.

questionAnswers(2)

yourAnswerToTheQuestion