Bei SFINAE geht es um Substitution. Also lass uns ersetzen!
template<
typename T,
std::enable_if_t<std::is_same<T, int>::value, T>* = nullptr>
void Add(T) {}
template<
typename T,
std::enable_if_t<!std::is_same<T, int>::value, T>* = nullptr>
void Add(T) {}
Becomes:
template<
class T=int,
int* = nullptr>
void Add(int) {}
template<
class T=int,
Substitution failure* = nullptr>
void Add(int) {
template<
class T=double,
Substitution failure* = nullptr>
void Add(double) {}
template<
class T=double
double* = nullptr>
void Add(double) {}
Ausfälle entfernen wir bekommen:
template<
class T=int,
int* = nullptr>
void Add(int) {}
template<
class T=double
double* = nullptr>
void Add(double) {}
Jetzt entfernen Template-Parameter-Werte:
template<
class T,
int*>
void Add(T) {}
template<
class T
double*>
void Add(T) {}
Dies sind verschiedene Vorlagen
Nun ist die eine, die bis verunstaltet:
template<
typename T,
typename = typename std::enable_if<std::is_same<T, int>::value, T>::type>
void Add(T) {}
template<
typename T,
typename = typename std::enable_if<!std::is_same<T, int>::value, T>::type>
void Add(T) {}
Becomes:
template<
typename T=int,
typename =int>
void Add(int) {}
template<
typename int,
typename = Substitution failure >
void Add(int) {}
template<
typename T=double,
typename = Substitution failure >
void Add(double) {}
template<
typename T=double,
typename = double>
void Add(double) {}
entfernen Ausfälle:
template<
typename T=int,
typename =int>
void Add(int) {}
template<
typename T=double,
typename = double>
void Add(double) {}
Und jetzt Template-Parameter-Werte:
template<
typename T,
typename>
void Add(T) {}
template<
typename T,
typename>
void Add(T) {}
Dies sind die gleichen Vorlagensignaturen. Und das ist nicht erlaubt, Fehler generiert.
Warum gibt es so eine Regel? Über den Rahmen dieser Antwort hinaus. Ich zeige einfach, wie die beiden Fälle unterschiedlich sind, und behaupte, dass der Standard sie unterschiedlich behandelt.
Wenn Sie einen nicht typisierten Vorlagenparameter wie den obigen verwenden, ändern Sie die Vorlagensignatur nicht nur die Vorlagenparameterwerte. Wenn Sie einen Typvorlagenparameter wie den obigen verwenden, ändern Sie nur die Vorlagenparameterwerte.
Stellen Sie sich vor, Sie schreiben zwei Funktionen 'Überladungen' wie diese: 'void Add (int = 0);' und 'void Add (int = 1)'. Sind sie wirklich anders? – Constructor
Mögliches Duplikat von [SFINAE für die Funktion der Klassenmitglieder (eine kompiliert die andere nicht)] (https://stackoverflow.com/questions/31625914/sfinae-for-class-member-function-one-compiles-the-other-not) – neonxc