C++之std::enable_if

相关系列文章

C++之std::is_object

C++之std::decay

C++模板函数重载规则细说

C++之std::declval

C++之std::move(移动语义)

C++之std::forward(完美转发)

C++之std::enable_if

C++之std::is_pod(平凡的数据)

目录

1.概述

2.函数返回值场景

3.函数参数场景

4.作为类模板或函数模板参数


1.概述

std::enable_if是C++11引入的模板结构体,在VS2019中<xtr1common>文件定义,它的原型是:

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;
};

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

        _Test如果是true, std::enable_if的type为_Ty;如果是false, type没有定义,这种情况在程序编译的时候就会报错,此元函数是活用 SFINAE ,基于类型特性条件性地从重载决议移除函数,并对不同类型特性提供分离的函数重载与特化的便利方法。 std::enable_if 可用作额外的函数参数(不可应用于运算符重载)、返回类型(不可应用于构造函数与析构函数),或类模板或函数模板形参

        因此std::enable_if可以以多种形式使用,它的作用主要有:

        1)通过函数的返回值,控制不同的条件下,选择不同的模板

        2)通过函数的参数,控制不同的条件下,选择不同的模板

        3)作为类模板或函数模板参数,控制不同的数据类型,选择不同的类模板或函数模板

下面就举例一一用示例说明它们的具体用法

2.函数返回值场景

#include <type_traits>
#include <iostream>

template <typename T>
typename std::enable_if <std::is_integral<T>::value, T>::type  addT(T value)
{
	return value + 10;
}

template <typename T>
typename std::enable_if <std::is_floating_point<T>::value, T>::type  addT(T value)
{
	return value + 5.0;
}

int main()
{
    int d = 10;
	double f = 20;
	d = addT(d);  //d = 20
	f = addT(f);  //f = 25.000000000
    return 0;
}

3.函数参数场景

示例1:

template <typename T>
T  addT(T  value, typename std::enable_if<std::is_integral<T>::value, T>::type* = nullptr)
{
	return value + 10;
}

template <typename T>
T  addT(T value, typename std::enable_if<std::is_floating_point<T>::value, T>::type* = nullptr)
{
	return value + 5;
}

int  main()
{
    int d = 10;
	double f = 20;
	d = addT(d);
	f = addT(f);
    return 0;
}

示例2:

#include <iostream>

// enabled via a parameter
template<class T>
void destroy(T *,
    typename std::enable_if<std::is_trivially_destructible<T>::value>::type * = 0) {
  std::cout << "destroying trivially destructible T\n";
}

// enabled via a non-type template parameter
template<class T, typename std::enable_if<!std::is_trivially_destructible<T>{} &&
            (std::is_class<T>{} || std::is_union<T>{}),bool>::type = true>
void destroy(T* t)
{
  std::cout << "destroying non-trivially destructible T\n";
}

int main() {
  int nValue = 1;
  std::string test = "hell";
  destroy(&nValue);
  destroy(&test);
  return 0;
}

输出如下:
destroying trivially destructible T
destroying non-trivially destructible T

示例3:

利用sprintf把数字或字符串转换为std::string, 根据格式化的不同,就用std::enable_if控制调用不同的转换函数,代码如下:

//1
template <int N>
std::string  tToString(char(&value)[N])
{
	std::string  temp;
	for (int i = 0; i < N; i++) {
		temp += value[i];
	}
	return temp;
}
//2
template <typename T>
std::string  tToString(T value, typename std::enable_if_t<std::is_same_v<T, bool>, T>* = 0) {
	char format[64] = { 0 };
	sprintf(format, "%s", value ? "true" : "false");
	return format;
}
//3
template <typename T>
std::string  tToString(T value, typename std::enable_if_t<std::is_same_v<T, const char*> ||
	std::is_same_v<T, char*> ||
	std::is_same_v<T, std::string>, T>* = 0) {
	return value;
}
//4
template <typename T>
std::string  tToString(T value, typename std::enable_if_t<std::is_integral_v<T> &&
	!std::is_same_v <T, bool>, T>* = 0) { //std::is_integral_v<T>, 整数
	char format[64] = { 0 };
	sprintf(format, "%d", value);
	return format;
}
//5
template <typename T>
std::string  tToString(T value, typename std::enable_if_t<std::is_floating_point_v<T>, T>* = 0) { //浮点数
	char format[64] = { 0 };
	sprintf(format, "%f", value);
	return format;
}
int main()
{
    std::string f = tToString(true);  //调用 2 版本函数
	f = tToString(100);               //调用 4 版本函数
	f = tToString("43634636");        //调用 3 版本函数
	f = tToString(88.4444);		      //调用 5 版本函数
	f = tToString(std::string("435236236")); //调用 3 版本函数

	char testT[] = "35353535345";
	f = tToString(testT);             //调用 1 版本函数

	char* pTest = testT;
	f = tToString(pTest);             //调用 3 版本函数

	const char* pTest1 = "ntrnrtnr44";
	f = tToString(pTest1);            //调用 3 版本函数
    
    return 0;
}

4.作为类模板或函数模板参数

struct T {
    enum { int_t,float_t } m_type;
    template <typename Integer,
              std::enable_if_t<std::is_integral_v<Integer>, int> = 0
    >
    T(Integer) : m_type(int_t) {}
 
    template <typename Floating,
              std::enable_if_t<std::is_floating_point_v<Floating>, int> = 0
    >
    T(Floating) : m_type(float_t) {} // OK
};
template <typename T, typename Enable = void>
class MyTestClass
{
	// 默认实现,适用于所有类型
public:
	MyTestClass() {
		std::cout << "default";
	}
};

template <typename T>
class MyTestClass<T, typename std::enable_if<std::is_integral<T>::value>::type>
{
	// 整型类型的特化实现
public:
	MyTestClass() {
		std::cout << "int";
	}
};

template <typename T>
class MyTestClass<T, typename std::enable_if<std::is_floating_point<T>::value>::type>
{
	// 浮点型类型的特化实现
public:
	MyTestClass() {
		std::cout << "float";
	}
};
int main()
{
	MyTestClass<std::string>  x1;// OK :匹配初等模板
	MyTestClass<int>  x2;        // OK :匹配偏特化 int 
	MyTestClass<double>  x3;     // OK :匹配偏特化 double
    return 0;
}

参考

std::enable_if - cppreference.com

  • 14
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值