C++模板元一生之友之:std::enable_if

你可以不懂模板元,但是你一定要懂enable_if, 因为你身边的朋友都悄悄地学会了enable_if, 并且让别人读不懂自己看起来很高端的代码。

std::enable_if 是 C++11 引入的一个工具,用于在编译时进行条件选择。它主要用来实现模板的 SFINAE(Substitution Failure Is Not An Error)机制,即在模板参数替换失败时不作为错误处理,而是选择其他可行的模板实例化。std::enable_if 常用于函数模板、类模板和重载中,以根据编译时条件启用或禁用特定的模板实例化。

std::enable_if 的基本用法

std::enable_if 位于 <type_traits> 头文件中,主要有两个模板参数:

  • 一个布尔条件 B
  • 一个类型 T,默认值为 void

如果 Btrue,则 std::enable_if<B, T>::type 定义为 T;如果 Bfalse,则 std::enable_if<B, T>::type 没有定义。

template <bool _Test, class _Ty = void>
struct enable_if {}; // no member "type" when !_Test

template <class _Ty>
struct enable_if<true, _Ty> { // type is _Ty for _Test
    using type = _Ty;
};

根据返回值选择模板

在如下示例中,foo 函数模板有两个重载版本,一个用于整数类型,一个用于浮点类型。std::enable_if 用于选择合适的模板实例化。【严格来说,这并不叫做函数重载版本,而是两个函数模板】

#include <type_traits>
#include <iostream>

// 只在T是整数类型时启用此函数
template<typename T>
typename std::enable_if<std::is_integral<T>::value, T>::type
foo(T value) {
    return value * 2;
}

// 只在T是浮点类型时启用此函数
template<typename T>
typename std::enable_if<std::is_floating_point<T>::value, T>::type
foo(T value) {
    return value * 0.5;
}

int main() {
    std::cout << foo(10) << std::endl;    // 输出20
    std::cout << foo(10.5) << std::endl;  // 输出5.25
    return 0;
}

根据模板参数类型进行重载

在下面示例中, 根据参数类型进行函数版本选择。

template<class T, typename std::enable_if_t<std::is_enum_v<T>, bool> = true >
void write(const T& t)
{
    std::cout << "write enum type" << std::endl;
}

//函数模板如果写成下面形式,可能更容易理解,这里给模板参数默认值,是为了调用函数不必传两个模板参数。
//template<class T, typename std::enable_if_t<std::is_enum_v<T>, bool> Flag = true >

template<class T, typename std::enable_if_t<!std::is_enum_v<T>, bool> = true>
void  write(const T& t)
{
    std::cout << "write non - enum typ" << std::endl;
}

enum MyEnum
{
    ONE = 1,
    TWO = 2
};

int main() {
    write(100); // write non - enum typ
    MyEnum my_enum;
    write(my_enum); // write enum type
	return 0;
}

    

在类模板中的使用

std::enable_if 也可以在类模板中使用,以控制类模板的部分或全部实例化。在下面示例中,MyClass 类模板有两个特化版本:一个用于整数类型,一个用于浮点类型。std::enable_if 用于控制特化版本的选择。

#include <type_traits>
#include <iostream>

// 只在T是整数类型时启用此类模板
template<typename T, typename Enable = void>
class MyClass;

// 特化版本:T是整数类型时, 这里特化版也是MyClass<T, void>,但会优先匹配到这个特化版
template<typename T>
class MyClass<T, typename std::enable_if<std::is_integral<T>::value>::type> {
public:
void display() {
    std::cout << "Integral type" << std::endl;
}
};

// 特化版本:T是浮点类型时,这里特化版也是MyClass<T, void>,但会优先匹配到这个特化版
template<typename T>
class MyClass<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
public:
void display() {
    std::cout << "Floating point type" << std::endl;
}
};

int main() {
    MyClass<int> intClass;
    intClass.display(); // 输出:Integral type

    MyClass<double> floatClass;
    floatClass.display(); // 输出:Floating point type

    return 0;
}

std::enable_if 是一种强大的工具,用于在编译时根据条件启用或禁用模板实例化。这对于编写通用的、类型安全的模板代码非常有用。通过结合 std::enable_if 与类型特性(如 std::is_integralstd::is_floating_point 等),可以实现非常灵活的模板编程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值