C++11模板元编程—std::enable_if使用说明

std::enable_if 顾名思义,满足条件时类型有效。作为选择类型的小工具,其广泛的应用在 C++ 的模板元编程中。它的定义也非常的简单:

// STRUCT TEMPLATE enable_if
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;
};

由此可知,只有当第一个模板参数_Testtrue 时,type 才有定义(type即第二个模板参数_Ty);否则使用 type 会产生编译错误,且默认模板参数可以让你不必指定类型。

另外enable_if_t是一个别名,其定义如下:

template <bool _Test, class _Ty = void>
using enable_if_t = typename enable_if<_Test, _Ty>::type;

std::enable_if可以用作函数参数、返回类型或类模板或函数模板参数,以有条件地从重载中删除函数或类。

一、作为函数参数

template<typename T>
struct Check1
{
    //如果T的类型是int,则定义函数 int read(void* = nullptr)
	template<typename U = T>
	U read(typename std::enable_if_t<std::is_same_v<U, int> >* = nullptr) {
		return 42;
	}
    
    //如果T的类型是double,则定义函数 double read(void* = nullptr)
	template<typename U = T>
	U read(typename std::enable_if_t<std::is_same_v<U, double> >* = nullptr) {
		return 3.14;
	}
};

使用示例

Check1<int> c1;
int x1 = c1.read();

Check1<double> c2;
double x2 = c2.read(0);

二、作为模板参数

template<typename T>
struct Check2
{
    //如果T的类型是int,则定义函数 int read()
	template<typename U = T, typename std::enable_if_t<std::is_same_v<U, int>, int> = 0>
	U read() {
		return 42;
	}
    
    //如果T的类型是double,则定义函数 double read()
	template<typename U = T, typename std::enable_if_t<std::is_same_v<U, double>, int> = 0>
	U read() {
		return 3.14;
	}
};

也可以写成如下形式:

template<typename T>
struct Check2
{
	template<typename U = T, typename std::enable_if_t<std::is_same_v<U, int>>* = nullptr>
	U read() {
		return 42;
	}

	template<typename U = T, typename std::enable_if_t<std::is_same_v<U, double>>* = nullptr>
	U read() {
		return 3.14;
	}
};

三、作为返回值类型

对于模板函数,有时希望根据不同的模板参数返回不同类型的值。

template<typename T>
struct Check3
{
    //如果T的类型是int,则定义函数 int read()
	template<typename U = T>
	typename std::enable_if_t<std::is_same_v<U, int>, U> read() {
		return 42;
	}

    //如果T的类型是double,则定义函数 double read()
	template<typename U = T>
	typename std::enable_if_t<std::is_same_v<U, double>, U> read() {
		return 3.14;
	}
};

利用auto关键字,可以写为如下形式:

// int goo<true>(int x)
template<bool B>
auto goo(int x) -> std::enable_if_t<B, int>
{
	return 1;
}

// int goo<false>(int x)
template<bool B>
auto goo(int x) -> std::enable_if_t<!B, int>
{
	return 2;
}

四、类型偏特化

在使用模板编程时,经常会用到根据模板参数的某些特性进行不同类型的选择,或者在编译时校验模板参数的某些特性。例如:

// T是其它类型
template<typename T, typename = void>
struct zoo;

// 如果T是浮点类型
template<typename T>
struct zoo<T, std::enable_if_t<std::is_integral_v<T>>>
{
};

五、concepts

C++20中利用concepts可以简化编写方式:

#ifdef __cpp_lib_concepts
#include <concepts>
#endif

// 如果T是整数类型
template<std::integral T>
void display_concepts_1(T num)
{
}

// 如果T是整数类型
void display_concepts(std::integral auto num)
{
}

// 如果T是浮点数类型
void display_concepts(std::floating_point auto num)
{
}

等价于如下形式:

// 如果T是整数类型
template<typename T, typename std::enable_if_t<std::is_integral_v<T>>* = nullptr>
void display_1(T num)
{
}

// 如果T是整数类型
template<typename T>
void display(typename std::enable_if_t<std::is_integral_v<T>>* = nullptr)
{
}

// 如果T是浮点数类型
template<typename T>
void display(typename std::enable_if_t<std::is_floating_point_v<T>>* = nullptr)
{
}
  • 7
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值