【C++ 】POD类型萃取

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_41035588/article/details/86449387

类型萃取依靠的就是模板的特化模板的特化又分为全特化与偏特化,对于编译器来说,如果你对某一功能有更好的实现,那么就应该使用你的特化版本。

一、函数模板特化

函数模板只有全特化,而没有偏特化。至于为什么没有偏特化,原因在于已经有了函数重载,偏特化也没什么用。

有时候并不总是能够写出对所有可能被实例化的类型都合适的模板,在某些情况下,通用模板定义对于某个类型可能是完全错误的,或者不能编译,或者做一些错误的事情。比如下面比较字符串的程序:

 	#include <iostream>
    using namespace std;
    template<typename T>
    int Compare(T str1, T str2)
    {
    	if (str1 > str2)
    		return 1;
    	if (str1 < str2)
    		return -1;
    	return 0;
    }
    int main()
    {
    	char *pStr1 = "abcd";
    	char *pStr2 = "wert";
    	cout<<Compare(pStr1, pStr2)<<endl;
    	system("pause");
    	return 0;
    }

结果如下:
在这里插入图片描述
当函数模板不能解决一些问题的时候,我们引入了模板函数特化。模板函数特化形式如下:

1)关键字template后面接一对空的尖括号<>2)函数名后接模板名和一对尖括号,尖括号中指定这个特化定义的模板形参。

3)函数形参表

4)函数体
template<>
返回值 函数名<Type>(参数列表)
{
	//函数体
}

注意:在模板特化版本的调用中,实参类型必须与特化版本函数的形参类型完全匹配,如果不匹配,编译器将为实参模板定义中实例化一个实例

#include <iostream>
using namespace std;
template<typename T>
T Compare(const T left, const T  right)
{
	return left > right ? left : right;
}
template<>
char const *Compare<const char*>(const char *const left, const char *const right)
{
	if (strcmp(left, right) > 0)
	{
		return left;
	}
	return right;}
int main()
{
	const char *const str1 = "abcde";
	const char *const str2 = "werty";	
	cout << Compare(str1, str2)<<endl;
	char* const str3 = "abcd";
	char* const str4 = "wwer";
	cout << Compare(str3, str4)<<endl;
	system("pause");
	return 0;
}

结果如下:
在这里插入图片描述
注意特化不能出现在模板实例的调用之后,应该在头文件中包含模板特化的声明,然后使用该特化版本的每个源文件包含该头文件。

二、类模板的全特化与偏特化

全特化与偏特化是相当于类模板而言的。全特化是限定死模板实现的具体类型,而偏特化是针对于当模板有多个类型时,限定了其中的一部分。

下面程序是一个模板类的全特化过程,我将它的模板类型分别限定为int、float:

#include <iostream>
using namespace std;

template<typename T1,typename T2>
class Specialization
{
public:
	void FuncTest(T1 _x, T2 _y)
	{
		cout << "_x:" << _x << endl;
		cout << "_y:" << _y << endl;
	}
};
//特化标志
template<>
class Specialization<int, float>  //全特化
{
public:
	void FuncTest(int _x, float _y)
	{
		cout << "_x:" << _x << endl;
		cout << "_y:" << _y << endl;
	}
};

int main()
{
	Specialization<int, char> _s;
	_s.FuncTest(3, 'x');
	system("pause");
	return 0;
}

结果如下:
在这里插入图片描述
模板类型T1与T2明确特化后,当我们实例化对象时,程序自然会去调用这个全特化的类 。一个类被称为全特化的条件:

1、必须有一个主模板类

2、模板类型必须全部明确化

3、类名与主模板类相同

下面是偏特化过程,在它的模板类型中,存在部分未被明确化的类型:

#include <iostream>
using namespace std;

template<typename T1,typename T2>
class Specialization
{
public:
	void FuncTest(T1 _x, T2 _y)
	{
		cout << "_x:" << _x << endl;
		cout << "_y:" << _y << endl;
	}
};

//偏特化
template<typename T>
class Specialization<int, T> //类型部分未明确,偏特化
{
public:
	void FuncTest(int _x, T _y)
	{
		cout << "_x:" << _x << endl;
		cout << "_y:" << _y << endl;
	}
};
int main()
{
	Specialization<int, char> _s;
	_s.FuncTest(3, 'x');
	system("pause");
	return 0;
}

结果如下:
在这里插入图片描述
我们仅对其中一个模板类型明确化,且存在一个未被明确的类型,这就是偏特化。一个类被称为偏特化的条件:

1、必须有一个主模板类

2、模板类型被部分明确化

3、类名与主模板类相同

注意:对于主模板类、全特化类、偏特化类的调用优先级的次序为:

全特化类 > 偏特化类 > 主模板类

三、内置类型的特化场景

当我们使用STL顺序表时,当类型为内置类型时会调用realloc开辟空间,但是,当类型为自定义类型时,调用realloc显然是不可以的,这时就应该调用new来实现。

STL中的Destroy算法根据函数的参数类型的特性:是否具有trivial destructor如果用户不定义析构函数,而是用系统自带的,则说明,析构函数基本没有什么用(但默认会被调用)我们称之为trivial destructor。反之,如果特定定义了析构函数,则说明需要在释放空间之前做一些事情,则这个析构函数称为non-trivial destructor。】来选择对应的策略来进行destroy,如果是内置类型,则不调用该类型的destructor否则对迭代器范围内的对象调用destructor来进行destroy。

总结类型萃取是在模板的基础上区分内置类型与自定义类型的,即将内置类型全部特化,然后再进行区分

四、POD类型萃取举例

下列程序中,我们利用C++类型萃取的技巧,可以将内置类型与自定义类型区分开来,然后对内置类型采用memcpy的方式进行拷贝,对自定义类型使用for循环拷贝。

#include <iostream>
using namespace std;

//POD:基本类型,指C++中与C兼容的类型

struct _TrueType
{
	bool Get()
	{
		return true;
	}
};

struct _FalseType
{
	bool Get()
	{
		return false;
	}
};

template<class _Tp>
struct TypeTraits
{
	typedef _FalseType _IsPODType;//如果不是内置类型,则IsPODType是FalseType 
};

//1.0
template<>
struct TypeTraits<bool>
{
	typedef _TrueType _IsPODType; //如果是内置类型则IsPODType是TrueType  
};
//2.0
template<>
struct TypeTraits<char>
{
	typedef _TrueType _IsPODType; //如果是内置类型则IsPODType是TrueType  
};
//3.0
template<>
struct TypeTraits<unsigned char>
{
	typedef _TrueType _IsPODType; //如果是内置类型则IsPODType是TrueType  
};
//4.0
template<>
struct TypeTraits<short>
{
	typedef _TrueType _IsPODType; //如果是内置类型则IsPODType是TrueType  
};
//5.0
template<>
struct TypeTraits<unsigned short>
{
	typedef _TrueType _IsPODType; //如果是内置类型则IsPODType是TrueType  
};
//6.0
template<>
struct TypeTraits<int>
{
	typedef _TrueType _IsPODType; //如果是内置类型则IsPODType是TrueType  
};
//7.0
template<>
struct TypeTraits<unsigned int>
{
	typedef _TrueType _IsPODType; //如果是内置类型则IsPODType是TrueType  
};
//8.0
template<>
struct TypeTraits<long>
{
	typedef _TrueType _IsPODType; //如果是内置类型则IsPODType是TrueType  
};
//9.0
template<>
struct TypeTraits<unsigned long>
{
	typedef _TrueType _IsPODType; //如果是内置类型则IsPODType是TrueType  
};
//10.0
template<>
struct TypeTraits<long long>
{
	typedef _TrueType _IsPODType; //如果是内置类型则IsPODType是TrueType  
};
//11.0
template<>
struct TypeTraits<unsigned long long>
{
	typedef _TrueType _IsPODType; //如果是内置类型则IsPODType是TrueType  
};
//12.0
template<>
struct TypeTraits<float>
{
	typedef _TrueType _IsPODType; //如果是内置类型则IsPODType是TrueType  
};
//13.0
template<>
struct TypeTraits<double>
{
	typedef _TrueType _IsPODType; //如果是内置类型则IsPODType是TrueType  
};
//14.0
template<>
struct TypeTraits<long double>
{
	typedef _TrueType _IsPODType; //如果是内置类型则IsPODType是TrueType  
};

//使用参数推导的萃取处理
template<class T>
void Copy(const T* src, T* dst, size_t size, _FalseType)
{
	cout << "_FalseType:" << typeid(T).name() << endl;
	for(size_t i = 0;i < size;++i)
	{
		dst[i] = src[i];
	}
}

template<class T>
void Copy(const T* src, T* dst, size_t size, _TrueType)
{
	cout << "_TrueType:" << typeid(T).name() << endl;
	memcpy(dst, src, sizeof(T)*size);
}
//使用萃取判断类型的Get函数判断是否是POD类型来处理

template<class T>
void Copy(const T* src, T* dst, size_t size)
{
	cout << "_TrueType:" << typeid(T).name() << endl;
	//内置类型,使用memcpy或for都可以拷贝
	if (TypeTraits<T>::_IsPODType().Get())
	{
		memcpy(dst, src, size * sizeof(T));
	}
	else
	{
		//用户自定义类型,采用for循环拷贝
		for (size_t i = 0; i < size; ++i)
		{
			dst[i] = src[i];
		}
	}
}
//测试
void Test()
{
	string s1[10] = { "1","2","3","4444444444444" };
	string s2[10] = { "11","22","33" };
	Copy(s1, s2, 10, TypeTraits<string>::_IsPODType());
	Copy(s1, s2, 10);
	int a1[10] = { 1,2,3 };
	int a2[10] = { 0 };
	Copy(a1, a2, 10, TypeTraits<int>::_IsPODType());
	Copy(a1, a2, 10);
}

int main()
{
	Test();
	system("pause");
	return 0;
}

参考博客:类型萃取

猜你喜欢

转载自blog.csdn.net/qq_41035588/article/details/86449387
今日推荐