std::enable_if
является типом, и я могу объявить переменные с ним:
std::enable_if<true, int> myVar;
Вы также можете написать:
std::enable_if<true, int> myVar2{};
std::enable_if<true, int> myVar3 = {};
У него нет конструктора, который принимаетцелое число, так что это не скомпилируется:
//Error - no way to convert 0 to std::enable_if<true, int>
std::enable_if<true, int> myVar = 0;
// Error - no way to convert nullptr to std::enable_if<true, int>
std::enable_if<true, int> myVar = nullptr;
Таким же образом, typename std::enable_if<true, int>::type*
является указателем (в частности, int*
).Ему можно присвоить 0, и ему также можно присвоить nullptr
:
// This works, because you can assign 0 to a pointer
typename std::enable_if<true, int>::type* myPtr = 0;
// This works, because you can assign nullptr to a pointer
typename std::enable_if<true, int>::type* myPtr = nullptr;
Как работает enable_if
. enable_if
построен нахак, при котором при определенных обстоятельствах компилятор просто игнорирует экземпляр шаблонной функции, если он не скомпилируется.(NB: если объявление компилируется, а тело нет, компилятор не может это игнорировать).
Допустим, у нас есть две версии функции, и вы хотите переключаться между ними на основе некоторого условия:
// This version gets called if T::value is true, because it'll fail to compile otherwise
template<class T, typename std::enable_if<T::value>::type* = nullptr>
void foo(){
std::cout << "T::value is true\n";
}
// This version gets called if T::value is false, because it'll fail to compile otherwise
template<class T, typename std::enable_if<not T::value>::type* = nullptr>
void foo(){
std::cout << "T::value is false\n";
}
Если у вас есть два класса, оба с constexpr value
член, он будет вызывать правильную версию функции:
class A{
public:
constexpr static bool value = true;
};
class B {
public:
constexpr static bool value = false;
};
int main() {
foo<A>(); // Prints T::value is true
foo<B>(); // Prints T::value is false
}