(C++模板编程):std::enable_if的使用(下)

目录

std::enable_if的使用

std::enable_if

std::enable_if源码

偏特化完全可以理解成一种(在编译期)条件分支语句。

std::enable_if基础认识

enable_if应用于函数模板

典型应用是作为函数模板的返回类型

enable_if_t (C++14)

enable_if用于类模板中

问题解决思路

[ 注 ]std::is_convertible(C++11)

应用范例

std::enable_if的使用

std::enable_if

  • C++11新标准中引入的类模板(结构模板),使用体现了C++编译器的SFINAE特性
  • 定位为一个helper模板(助手模板),用于辅助其他模板的设计,表现一种:编译期的分支逻辑(编译期就可以确定走哪条分支)。
template <typename T>
struct MEB
{
	using type = T;
};
  • 调用
MEB<int>::type abc = 15; //MEB<int>::type 就代表int类型

std::enable_if源码

// STRUCT TEMPLATE enable_if
template <bool _Test, class _Ty = void>   //泛化版本
struct enable_if {}; // no member "type" when !_Test

template <class _Ty> //偏特化版本:怎么理解:只有这个偏特化版本存在,才存在一个名字叫做type的类型别名(类型)
struct enable_if<true, _Ty> { // type is _Ty for _Test
	using type = _Ty;
};

偏特化完全可以理解成一种(在编译期)条件分支语句。

  • 编译期就知道哪个条件成立。

std::enable_if基础认识

std::enable_if< (3 > 2)>::type* mypoint1 = nullptr;  //相当于 void *mypoint1 = nullptr
  • 上面std::enable_if第一个参数为true,则执行偏特化版本分支,有type类型,且泛化版本已经给出了第二个参数的默认值为void,即type为void。
std::enable_if< (3 < 2)>::type* mypoint1 = nullptr;
  • 上面std::enable_if第一个参数为false,执行泛化版本分支,泛化版本中没有type类型,所以报错。

enable_if应用于函数模板

典型应用是作为函数模板的返回类型

template <typename T>
typename std::enable_if<(sizeof(T) > 2)>::type funceb() 
{
	//...
}
  • 调用
funceb<int>();
  • 由于sizeof(int) 大于 2,即走偏特化版本分支,此时第二个参数为默认值void,所以模板实例化为void funceb(){}。
  • 若调用如下
funceb<char>();
  • sizeof(char) 小于2 不满足条件,即不符合这个函数模板,此模板被忽略掉,去寻找其他的funceb函数模板或函数,但是未能找到,报如下错误

 

enable_if_t (C++14)

template <bool _Test, class _Ty = void>
using enable_if_t = typename enable_if<_Test, _Ty>::type; //别名模板
  • 可进行如下替换
template <typename T>
typename std::enable_if<(sizeof(T) > 2)>::type funceb() 
{
	//...
}

/******替换为*******/

template <typename T>
std::enable_if_t<(sizeof(T) > 2)> funceb() 
{
	//...
}

应用案例

template <typename T>
std::enable_if_t<(sizeof(T) > 2),T> funceb()
{
	T myt = {};
	return myt;
}
  • 调用
funceb<int>();
  • 模板实例化为int funceb(){}

enable_if用于类模板中

class Human
{
public:
	//构造函数模板
template<typename T>
    Human(T&& tmpname) : m_sname(std::forward<T>(tmpname))
    {
        cout << "Human(T&& tmpname)执行" << endl;
    }
    //拷贝构造函数
Human(const Human& th) : m_sname(th.m_sname)
{
	cout << "Human(const Human& th)拷贝构造函数执行" << endl;
}
 
//移动构造函数
Human(Human&& th) : m_sname(std::move(th.m_sname))
{
	cout << "Human(Human&& th)移动构造函数执行" << endl;
}
 
 
private:
	string m_sname;
};
  • 调用
string sname = "ZhangSan";
Human myhuman1(sname);
 
Human myhuman3(myhuman1); 
  • 问题:实际编译器去调用了构造函数模板,而不是调用了拷贝构造函数。 

问题解决思路

  • 针对构造函数模板,如果给进来的参数是一个string类型的参数,就让这个构造函数模板生效
  • 否则就让这个构造函数模板被忽略即可。也就是说,如果使用enable_if于构造函数模板中,enable_if的条件只需要设置成“形参类型==string类型”即可

[ 注 ]std::is_convertible(C++11)

  • 一两个模板参数分别是From 和To:用于判断能否从某个类型隐式的转换到另外一个类型。
  • 返回一个bool值——true或者false。
cout << "string=>float:" << std::is_convertible<string, float>::value << endl;  //0
cout << "float=>int:" << std::is_convertible<float, int>::value << endl;    //1

应用范例

class Human
{
//给类型模板定义一个别名(别名模板)
template <typename T>
using StrProcType = std::enable_if_t<std::is_convertible<T, std::string>::value >;
 
public:
	//构造函数模板
template<
	typename T,
    typename = StrProcType<T>
       //如果T能够成功转换成std::string类型,那么typename  = void				             
>
    Human(T&& tmpname) : m_sname(std::forward<T>(tmpname))
    {
        cout << "Human(T&& tmpname)执行" << endl;
    }
    //拷贝构造函数
Human(const Human& th) : m_sname(th.m_sname)
{
	cout << "Human(const Human& th)拷贝构造函数执行" << endl;
}
 
//移动构造函数
Human(Human&& th) : m_sname(std::move(th.m_sname))
{
	cout << "Human(Human&& th)移动构造函数执行" << endl;
}
 
 
private:
	string m_sname;
};
  • 调用
string sname = "ZhangSan";
Human myhuman1(sname);
 
Human myhuman3(myhuman1); 
  • 构造函数模板通过判断传入的参数类型是否为string,来判断执行还是忽略该模板,
  • Human myhuman3(myhuman1); 传入的不是string类型,所以自动忽略构造函数模板,转而调用拷贝构造函数。
  • 输出

  • 11
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值