Überladung der Template-Funktion mit identischen Signaturen, warum funktioniert das?

Minimales Programm:

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

Ausgabe:

    1 

Warum führt dies nicht zu einem Kompilierungsfehler? Wenn der Vorlagencode generiert wird, würden die Funktionen nichtint foo(typename T::type search) undint foo(S& search) die gleiche Unterschrift haben?

Wenn Sie die Signatur der Vorlagenfunktion ein wenig ändern, funktioniert dies weiterhin (wie im obigen Beispiel zu erwarten):

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

Dies ist jedoch nicht der Fall, und der einzige Unterschied besteht darin, dass einer eine int-Signatur hat und der andere durch den ersten Template-Parameter definiert wird.

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

Compilerfehler (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.

Ich verwende ähnlichen Code für ein Projekt, an dem ich arbeite, und ich befürchte, dass die Sprache, die ich nicht verstehe, subtil ist und in bestimmten Fällen ein undefiniertes Verhalten hervorruft. Ich sollte auch erwähnen, dass es sowohl auf Clang als auch in VS11 kompiliert, also denke ich nicht, dass es nur ein Compiler-Fehler ist.

Edit: Zweiter Fall korrigiert (Tippfehler); Fehlermeldung von Clang hinzugefügt.

Edit # 2: Für diejenigen unter Ihnen, die gefragt haben, was T :: type bedeutet.

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

template <bool B, class T = void> struct enable_if;

Wenn B wahr ist, hat std :: enable_if einen public member typedef-Typ, der gleich T ist. Andernfalls gibt es kein Mitglied typedef.

enable_if ist eine Struktur. Wenn der im ersten Template-Parameter von enable_if ausgewertete Ausdruck wahr ist (und im Fall meiner obigen Beispiele ist dies der Fall), gibt es grundsätzlich ein öffentliches Mitgliedtype Das hat den gleichen Typ wie der zweite Template-Parameter.

Im Falle vonenable_if<true, int>, enable_if :: type hat den Typ int.

Antworten auf die Frage(2)

Ihre Antwort auf die Frage