Это просто, как работает SFINAE;)
Как вы знаете, вы должны "создать ошибку" в объявлении шаблона, а не в определении шаблона.Как это:
template < typename X, typename = ... here is the code which may generate an error during instantiation >
void Bla() {}
Единственный шанс вставить некоторый «код» в объявление - это определить что-то в списке параметров шаблона или внутри самого объявления функции шаблона, например:
template < typename X>
void Bla( ... something which may generates an error ) {}
Пример:
template <typename T, typename = std::enable_if_t< std::is_same_v< int, T>>>
void Bla()
{
std::cout << "with int" << std::endl;
}
template <typename T, typename = std::enable_if_t< !std::is_same_v< int, T>>>
void Bla(int=0)
{
std::cout << "with something else" << std::endl;
}
int main()
{
Bla<int>();
Bla<std::string>();
}
Но каков здесь фон "создания ошибки замещения"?
Хитрость где-то позади std::enable_if
.Мы также можем использовать его без этого:
template <typename T, typename = char[ std::is_same_v< int, T>]>
void Bla()
{
std::cout << "with int" << std::endl;
}
template <typename T, typename = char[ !std::is_same_v< int, T>]>
void Bla(int=0)
{
std::cout << "with something else" << std::endl;
}
Взгляните на: typename = char[ !std::is_same_v< int, T>]
Здесь std::is_same_v
возвращает нам значение bool, которое преобразуется в 0, если оно недействительно, и в любое положительное число, если оно допустимо.,А создание char[0]
- это просто ошибка в c ++!Таким образом, с отрицанием нашего выражения с !
мы получили один для «is int» и один для «is int».Как только он пытается создать массив размера 0, что является ошибкой, и шаблон не будет создан, и как только он генерирует тип char[!0]
, который является допустимым выражением.
И в качестве последнего шага:
... typename = ...
подразумевается как: здесь будет определен тип, здесь без имени параметра шаблона, так как сам параметр не используется позже.Вы также можете написать:
... typename X = ...
, но поскольку X не используется, оставьте его!
Резюме: Вы должны предоставить некоторый код, который генерирует ошибку или нет, в зависимости от типаили значение данного выражения.Выражение должно быть частью объявления функции или частью списка параметров шаблона. не разрешено помещать ошибку в определение функции / класса, так как это больше не будет "не ошибкой" в смысле SFINAE.
Обновление: могут результатыВыражения SFINAE используются для дальнейших выражений: Да
Пример:
template < typename TYPE >
void CheckForType()
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
template <typename T, typename X = std::enable_if_t< std::is_same_v< int, T>, float>>
void Bla()
{
std::cout << "with int" << std::endl;
CheckForType<X>();
}
template <typename T, typename X = std::enable_if_t< !std::is_same_v< int, T>, double >>
void Bla(int=0)
{
std::cout << "with something else" << std::endl;
CheckForType<X>();
}
int main()
{
Bla<int>();
Bla<std::string>();
}
Вывод:
with int
void CheckForType() [with TYPE = float]
with something else
void CheckForType() [with TYPE = double]
Объяснение: std::enable_if
имеет второй параметр шаблона, который используетсяв качестве возвращаемого типа, если его первым параметром будет true
.Как этот, вы можете использовать этот тип здесь.Как видите, функция CheckForType
вызывается с этим определенным типом для X
из выражения SFINAE.