文章目录
前言:
std::enable_if_t
是 C++14 引入的一个模板元编程工具,它是std::enable_if
的便捷别名。std::enable_if
定义在<type_traits>
头文件中,主要用于在编译时根据条件来启用或禁用某个模板实例化,从而实现更灵活的泛型编程。下面详细介绍std::enable_if_t
的作用和使用场景。
一、enable_if_t
模版
1、基本原理
std::enable_if
是一个模板结构体,它有两个模板参数:一个布尔常量B
和一个类型T
(T
有默认值void
)。当B
为true
时,std::enable_if<B, T>
有一个嵌套类型type
,其值为T
;当B
为false
时,std::enable_if<B, T>
没有type
成员。
std::enable_if_t<B, T>
是typename std::enable_if<B, T>::type
的别名,使用起来更加简洁。
2、源码实现
std::enable_if_t
是 C++14 引入的一个便捷类型别名,它定义在<type_traits>
头文件中,其核心依赖于std::enable_if
模板结构体。下面我们来详细分析std::enable_if
和std::enable_if_t
的源码实现。
2.1、std::enable_if
的实现
std::enable_if
是一个模板元编程工具,它根据一个编译时布尔条件来决定是否定义一个嵌套类型type
。以下是其简化的实现代码:
// 主模板,当条件为 false 时,没有 type 成员
template <bool B, class T = void>
struct enable_if {};
// 特化版本,当条件为 true 时,定义 type 成员为 T
template <class T>
struct enable_if<true, T> {
using type = T;
};
代码解释
- 主模板:
template <bool B, class T = void> struct enable_if {};
是std::enable_if
的主模板。当布尔条件B
为false
时,这个结构体没有嵌套类型type
。在模板实例化时,如果尝试访问enable_if<false, T>::type
,会导致编译错误,因为该类型不存在。 - 特化版本:
template <class T> struct enable_if<true, T> { using type = T; };
是std::enable_if
的特化版本,当布尔条件B
为true
时,这个结构体定义了一个嵌套类型type
,其值为模板参数T
。
2.2、 std::enable_if_t
的实现
std::enable_if_t
是std::enable_if
的便捷别名,它通过typename
关键字来访问std::enable_if
的type
成员。以下是其实现代码:
// std::enable_if_t 的实现
template <bool B, class T = void>
using enable_if_t = typename enable_if<B, T>::type;
代码解释
template <bool B, class T = void>
:定义了两个模板参数,B
是一个布尔常量,用于表示条件;T
是一个类型参数,有默认值void
。using enable_if_t = typename enable_if<B, T>::type;
:使用using
关键字定义了一个类型别名enable_if_t
。typename
关键字用于告诉编译器enable_if<B, T>::type
是一个类型。当B
为true
时,enable_if<B, T>::type
存在,enable_if_t
就是T
;当B
为false
时,enable_if<B, T>::type
不存在,尝试使用enable_if_t
会导致编译错误。
3、使用示例
3.1、限制模板参数的类型
下面是一个简单的使用示例,展示了
std::enable_if_t
的应用:
#include <iostream>
#include <type_traits>
// 只允许整数类型的模板函数
template <typename T>
std::enable_if_t<std::is_integral_v<T>, T>
add(T a, T b) {
return a + b;
}
int main() {
int result = add(1, 2);
std::cout << "Result: " << result << std::endl;
// 以下代码会导致编译错误,因为 double 不是整数类型
// double doubleResult = add(1.0, 2.0);
return 0;
}
代码解释
std::is_integral_v<T>
是 C++17 引入的便捷写法,等价于std::is_integral<T>::value
,用于判断T
是否为整数类型。std::enable_if_t<std::is_integral_v<T>, T>
作为函数返回类型,当T
为整数类型时,std::is_integral_v<T>
为true
,std::enable_if_t<std::is_integral_v<T>, T>
就是T
,函数可以正常实例化;当T
不是整数类型时,std::is_integral_v<T>
为false
,std::enable_if_t<std::is_integral_v<T>, T>
不存在,会导致编译错误。
通过以上分析,我们可以看到
std::enable_if_t
是如何基于std::enable_if
实现编译时条件选择的,它在泛型编程中非常有用,可以帮助我们根据不同的类型特性选择不同的函数或类实现。
3.2 函数模板的重载和选择
在编写函数模板时,可能需要根据不同的条件选择不同的函数实现。
std::enable_if_t
可以帮助我们在编译时根据类型特性来选择合适的函数模板。
示例代码:
#include <iostream>
#include <type_traits>
// 处理整数类型的函数
template <typename T>
std::enable_if_t<std::is_integral_v<T>, void>
process(T value) {
std::cout << "Processing integral type: " << value << std::endl;
}
// 处理浮点类型的函数
template <typename T>
std::enable_if_t<std::is_floating_point_v<T>, void>
process(T value) {
std::cout << "Processing floating-point type: " << value << std::endl;
}
int main() {
int intValue = 42;
double doubleValue = 3.14;
process(intValue);
process(doubleValue);
return 0;
}
代码解释:
std::is_integral_v<T>
是std::is_integral<T>::value
的 C++17 便捷写法,用于判断T
是否为整数类型。std::is_floating_point_v<T>
用于判断T
是否为浮点类型。- 当调用
process
函数时,编译器会根据传入的参数类型进行模板实例化。如果传入的是整数类型,第一个process
函数模板的std::enable_if_t
条件为true
,该函数模板会被实例化;如果传入的是浮点类型,第二个process
函数模板的std::enable_if_t
条件为true
,该函数模板会被实例化。
3.3、类是指定类的子类才允许实例化
有一系列的类继承自
BaseObject
,要提供一个接口获取这个类或子类(以模版参数的形式传入)的实例
template<typename T,
typename std::enable_if_t<std::is_base_of<BaseObject, T>::value, int> = 0>
std::vector<T> GetTargetObj()
{
// ...
}