std::enable_if
是 C++
中的一种 SFINAE
(Substitution Failure Is Not An Error)工具,用于在模板中启用或禁用某些函数或类的特化。它通常用于条件编译,允许我们根据模板参数的某些特性(如类型是否满足某些条件)来选择性地启用或禁用某些代码。
基本语法
std::enable_if
定义在 <type_traits>
中,其基本形式如下:
1 2
| template<bool B, class T = void> struct enable_if {};
|
- 如果
B
为 true
,std::enable_if
定义一个类型 T
(默认为 void
)。
- 如果
B
为 false
,std::enable_if
不定义任何类型,从而导致模板匹配失败(SFINAE
)。
可以使用 std::enable_if_t
简化代码:
1 2
| template<bool B, class T = void> using enable_if_t = typename enable_if<B, T>::type;
|
使用场景
函数模板的启用/禁用
通过 std::enable_if
,我们可以根据模板参数的某些条件,选择性地启用或禁用某些函数模板。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #include <iostream> #include <type_traits>
template <typename T> typename std::enable_if<std::is_integral<T>::value, void>::type print(T value) { std::cout << "Integer: " << value << std::endl; }
template <typename T> typename std::enable_if<!std::is_integral<T>::value, void>::type print(T value) { std::cout << "Not an integer: " << value << std::endl; }
int main() { print(42); print(3.14); return 0; }
|
std::is_integral<T>::value
是一个类型特性,用于判断 T
是否是整数类型。
std::enable_if
根据这个条件启用或禁用对应的函数模板。
使用 enable_if_t
简化代码
在 C++14 中,可以使用 std::enable_if_t
简化代码,避免显式写 typename
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #include <iostream> #include <type_traits>
template <typename T> std::enable_if_t<std::is_integral<T>::value, void> print(T value) { std::cout << "Integer: " << value << std::endl; }
template <typename T> std::enable_if_t<!std::is_integral<T>::value, void> print(T value) { std::cout << "Not an integer: " << value << std::endl; }
int main() { print(42); print(3.14); return 0; }
|
构造函数的启用/禁用
std::enable_if
也可以用于类的构造函数中,选择性地启用某些构造函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| #include <iostream> #include <type_traits>
class MyClass { public: template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>> MyClass(T value) { std::cout << "Constructed with integer: " << value << std::endl; }
template <typename T, typename = std::enable_if_t<!std::is_integral<T>::value>> MyClass(T value) { std::cout << "Constructed with non-integer: " << value << std::endl; } };
int main() { MyClass obj1(42); MyClass obj2(3.14); return 0; }
|
- 通过模板参数
typename = std::enable_if_t<...>
,我们可以根据类型特性选择性地启用某些构造函数。
std::enable_if_t
的默认模板参数(typename = ...
)不会影响函数签名,因此可以用于构造函数的重载。
类模板的部分特化
std::enable_if
也可以用于类模板的部分特化,选择性地启用某些类模板。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| #include <iostream> #include <type_traits>
template <typename T, typename Enable = void> class MyClass;
template <typename T> class MyClass<T, std::enable_if_t<std::is_integral<T>::value>> { public: void print() { std::cout << "Integer specialization" << std::endl; } };
template <typename T> class MyClass<T, std::enable_if_t<!std::is_integral<T>::value>> { public: void print() { std::cout << "Non-integer specialization" << std::endl; } };
int main() { MyClass<int> obj1; obj1.print();
MyClass<double> obj2; obj2.print();
return 0; }
|
- 主模板
MyClass
是一个空模板,只有在特化时才会启用。
- 使用
std::enable_if_t
根据类型特性选择性地启用某些特化。