C++模板编程-enable_if
std::enable_if的使用
对于重载的函数或者函数模板的选择上,编译器内部有一个自己的规则,并不是简单粗暴的对函数就优先选择,对函数模板就靠后选择
替换失败并不是一个错误(SFINAE):Substitution Failure Is Not An Error,SFINAE看成是C++语言的一种特性或者说一种模板设计中要遵循的重要原则
针对函数模板而言,当用一个具体类型替换函数模板的参数时,可能会产生意想不到的问题:,比如产生一些毫无意义甚至是看起来语法上有错误的代码,对于这些代码,编译器并不一定报错,有可能是忽略。编译器认为这个函数模板不匹配针对本次的函数调用,就当这个函数不存在一样。转而去选择其他更匹配的函数或者函数模板
基础认识:C++11新标准中引入的类模板(结构模板。使用体现了C++编译器的SFINAE特性)
定位为一个helper模板(助手模板),用于辅助其他模板的设计,表现一种:编译器的分支逻辑(编译器就可以确定走哪条分支)
namespace nmsp1 { template<typename T> struct MEB { using type = T; }; } >查看下enable_id的源码 nmsp1::MEB<int>::type abc = 1; //就代表int类型
怎么理解这个篇特化版本:只有这个偏特化版本存在,才存在一个名字叫做type的类型别名(类型)
偏特化完全可以理解为一种编译器的条件分支语句
std::enable_if<true>::type* mypoint1 = nullptr; //第二个有默认值,所以第二个采用void,那么type就是void std::enable_if<false>::type* mypoint1 = nullptr; //走的是泛化版本,false没有type这个别名
范例:enable_if用于函数模板中,典型应用是作为函数模板的返回类型
template<typename T> typename std::enable_if<(sizeof(T) > 2)>::type funceb() { //.... } nmsp2::funceb<int>();//void funceb(){} nmsp2::funceb<char>();//error:未找到匹配的重载函数,条件不满足 //C++14出了这个等同上面 template<typename T> std::enable_if_t<(sizeof(T) > 2),T> funceb() { T myt = {}; return myt; } nmsp2::funceb<int>();//int funceb(){} //nmsp2::funceb<char>();
如果是第一条语句:如果funceb函数模板中涉及到enable_if_t中的条件成立的时候,这个funceb代表是一个类型,如果是第二条,条件不成立,那么有SFINAE的特性存在,请编译器忽略我这个funceb的这个函数模板吧。那么对第二条语句上例的funceb这个函数模板是不存在那样
enable_if_t源码,别名模板
示例:用于类模板中
万能引用
namespace nmsp3 { 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 = "zhangshan"; nmsp3::Human myhuman(sname); // nmsp3::Human myhuman3(myhuman);//实际编译器调用构造函数模板,而不是拷贝构造函数
代码解决,针对构造函数,如果给进来的参数是一个string类型的参数,就让这个构造函数模板生效,否则就让这个构造函数模板被忽略即可,也就是说,如果使用enable_if于构造函数模板中,enable_if的条件只需要设置成"形参类型==string
std::is_convertible,C++11引入的,两个模板参数分别是From 和 To:用于判断能否从某个类型隐式的准换到另外一个类型,返回是布尔值
cout << "string=>float: " << std::is_convertible<string, float>::value << endl; //string=>float: 0 cout << "float>=int: " << std::is_convertible<float, int>::value << endl; //float>=int: 1
解决方案
namespace nmsp4 { //别名模板 template<typename T> using StrProcType = std::enable_if_t<std::is_convertible<T, std::string>::value>; class Human { public: //构造函数模板 template< typename T, typename = std::enable_if_t<std::is_convertible<T,std::string>::value> //如果T能够成功转换成std::string类型,那么typename = void //typename = StrProcType<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 = "zhangshan"; nmsp4::Human myhuman(sname); nmsp4::Human myhuman3(myhuman);//成功调用拷贝函数 private: string m_sname; }; } string sname = "zhangshan"; nmsp4::Human myhuman(sname); nmsp4::Human myhuman3(myhuman);//成功调用拷贝函数
https://blog.csdn.net/baidu_41388533/article/details/109689556
https://blog.csdn.net/baidu_41388533/article/details/109702574