C++ 新特性 | C++ 14 | enable_if_t 模版


前言:

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 和一个类型 TT 有默认值 void)。当 Btrue 时,std::enable_if<B, T> 有一个嵌套类型 type,其值为 T;当 Bfalse 时,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_ifstd::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 的主模板。当布尔条件 Bfalse 时,这个结构体没有嵌套类型 type。在模板实例化时,如果尝试访问 enable_if<false, T>::type,会导致编译错误,因为该类型不存在。
  • 特化版本template <class T> struct enable_if<true, T> { using type = T; };std::enable_if 的特化版本,当布尔条件 Btrue 时,这个结构体定义了一个嵌套类型 type,其值为模板参数 T

2.2、 std::enable_if_t 的实现

std::enable_if_tstd::enable_if 的便捷别名,它通过 typename 关键字来访问 std::enable_iftype 成员。以下是其实现代码:

// 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_ttypename 关键字用于告诉编译器 enable_if<B, T>::type 是一个类型。当 Btrue 时,enable_if<B, T>::type 存在,enable_if_t 就是 T;当 Bfalse 时,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>truestd::enable_if_t<std::is_integral_v<T>, T> 就是 T,函数可以正常实例化;当 T 不是整数类型时,std::is_integral_v<T>falsestd::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()
{
    // ...
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值