相关系列文章
目录
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;
}
参考