dokumentacji Microsoftu there nie jest tak jasne jak słońce. Zamiast tego użyj this.
Zapewnienie szablon funkcji z nienazwanej domyślnej parametru w postaci:
typename enable_if<your_condition, void **>::type = nullptr
(jak sugeruje MS pisarz), jest przydatna w przypadku - i tylko w przypadku - chcesz napisać kilka przeciążeniem szablon funkcji o różnych zachowaniach , które są kontrolowane przez jeden lub więcej argumentów szablonu. Następnie, przez , zastępując your_condition
warunkiem spełniającym odpowiednie wymaganie dla argumentu szablonu, można zarejestrować zasadę SFINAE , aby wybrać konkretne przeciążenie, które ma być tworzone dla określonych argumentów szablonu.
Parametr SFINAE - nazwijmy to - jest nieużywany przez instancjonowaną funkcję; istnieje wyłącznie w celu sprowokowania SFINAE w szablonie funkcji . W związku z tym może być bezimienny, a więc musi być domyślnie: nie może wymuszać dostarczenia dodatkowego, bezużytecznego argumentu, gdy użytkownik wywoła szablon funkcji.
Na przykład:
#include <type_traits>
#include <iostream>
template <typename T>
T foo(T && t,
typename std::enable_if<std::is_same<T,int>::value, void **>::type = nullptr)
{
std::cout << "Doubling " << t << " gives " << (t + t) << std::endl;
return t + t;
}
template <typename T>
T foo(T && t,
typename std::enable_if<!std::is_same<T,int>::value, void **>::type = nullptr)
{
std::cout << "Squaring " << t << " gives " << (t * t) << std::endl;
return t * t;
}
using namespace std;
int main()
{
cout << foo(2) << endl;
cout << foo(3.3) << endl;
return 0;
}
wyjściowa wynosi:
Doubling 2 gives 4
4
Squaring 3.3 gives 10.89
10.89
W tych dwóch przeciążeń funkcji szablonu foo
, pierwszy podwaja to typ T
argumentem a drugi kwadraty jej argument, a parametr SFINAE służy do stwierdzenia, że podwojenie obciążenia zostanie utworzone jako , jeśli T
jest int
i że przeciążenie kwadraturowe zostanie wybrane inaczej.
Kiedy T
jest int
warunek:
!std::is_same<T,int>::value
który kontroluje parametry SFINAE przeciążenia kwadratury jest fałszywe. W związku z tym specyfikator typu:
typename std::enable_if<!std::is_same<T,int>::value, void **>::type = nullptr
nie można skompilować. To jest niepowodzenie substytucji w rozdzielczości szablonu. W przypadku przeciążenia do kwadratu zastępowanie dla jest nieprzewidywalne: . Przeciążenie do kwadratu jest więc eliminowane z biegu, a jedynie dublowanie jest pozostawione do utworzenia wywołania funkcji w postaci .
Kiedy T
jest (powiedzmy) double
i nie int
, następnie dokładnie odwrotnie dzieje i tylko przeciążenie kwadratury przetrwa rozdzielczość matrycy. Zadzwoń pod foo(2)
, a otrzymasz podwojenie. Zadzwoń pod numer foo(3.3)
, a otrzymasz kwadraturę.
Parametr MS Parametr SFINAE tutaj jest niepotrzebnie długi.
template< bool B, class T = void >
struct enable_if;
według C++ 11 standardowych a później domyślne T
do void
. Tak jak od:
typename std::enable_if<some_condition, void **>::type = nullptr
może być równie dobrze w skrócie:
typename std::enable_if<some_condition>::type * = nullptr
a od C++ 14 Standard posiada:
template< bool B, class T = void >
using enable_if_t = typename enable_if<B,T>::type
tak samo możliwe, parametr SFINAE być dodatkowo skrócone do:
std::enable_if_t<some_condition> * = nullptr
Stosowanie SFINAE szablonu funkcji parametr do sprawy, że wskazał w swoim poście , byś napisać jak się z:
enum ops {
add,
multiply
};
template<ops Op>
int op(int const & lhs, int const & rhs,
std::enable_if_t<Op == add> * = nullptr)
{
return lhs + rhs;
}
template<ops Op>
int op(int const & lhs, int const & rhs,
std::enable_if_t<Op == multiply> * = nullptr)
{
return lhs * rhs;
}
...
auto i = op<add>(2,3);
auto j = op<multiply>(2,3);
...
// C++14
Może to być przydatne, gdy (ab) w rozdzielczości przeciążenia na przykład. – BartoszKP
Nie można osiągnąć części "omull". – Jarod42
enable_if włącza funkcję, a nie parametr. –