SFINAE riguarda la sostituzione. Quindi sostituiamoci!
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) {}
diventa:
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) {}
Rimuovere fallimenti otteniamo:
template<
class T=int,
int* = nullptr>
void Add(int) {}
template<
class T=double
double* = nullptr>
void Add(double) {}
Ora parametro di modello rimuovere i valori:
template<
class T,
int*>
void Add(T) {}
template<
class T
double*>
void Add(T) {}
Questi sono diversi modelli.
Ora quello che scombina:
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) {}
diventa:
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) {}
Rimuovi fallimenti:
template<
typename T=int,
typename =int>
void Add(int) {}
template<
typename T=double,
typename = double>
void Add(double) {}
Ed ora i valori dei parametri del modello:
template<
typename T,
typename>
void Add(T) {}
template<
typename T,
typename>
void Add(T) {}
Queste sono le stesse firme del modello. E questo non è permesso, errore generato.
Perché esiste una regola del genere? Oltre lo scopo di questa risposta. Sto semplicemente dimostrando come i due casi sono diversi e affermando che lo standard li tratta in modo diverso.
Quando si utilizza un parametro di modello non di tipo come sopra, si modifica la firma del modello non solo i valori dei parametri del modello. Quando si utilizza un parametro del modello di tipo come sopra, si modificano solo i valori dei parametri del modello.
Immaginate di scrivere due "overload" di funzione come questi: 'void Add (int = 0);' e 'void Add (int = 1)'. Sono davvero diversi? – Constructor
Possibile duplicato di [SFINAE per la funzione membro della classe (uno non compila l'altro)] (https://stackoverflow.com/questions/31625914/sfinae-for-class-member-function-one-compiles-the-other-non) – neonxc