再谈模板(非类型模板参数,模板特化,模板特化的应用,类型萃取, 模板的分离编译, 模板的优缺点)

再谈模板

1、非类型模板参数

模板参数分为类类型参数和非类型参数
类类型参数:出现在模板参数列表中,跟在class或者typename的参数类型名称
非类型参数:就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可以将该参数当成常量使用

注:
1、浮点数,类对象以及字符串不允许作为非类型模板参数
2、非类型模板参数必须在编译器就能确认结果

#include <iostream>

using namespace std;

namespace gwp
{
	//定义一个模板类型的静态数组
	template<class T, size_t N= 10>
	class array
	{
	public:
		T& operator(size_t index)
		{
			return m_array[index];
		}

		const T& operator(size_t index) const
		{
			return m_array[index];
		}

		size_t size() const
		{
			return m_size;
		}

		bool empty() const
		{
			return (m_size == 0) ? true : false;
		}
	private:
		T m_array[N];
		size_t m_size;
	};
}

int main()
{

	system("pause");
	return 0;
}

2、模板特化

模板的特化:
模板在遇到一些特殊类型的时候会出错,就需要对模板进行特化
模板的特化分为类模板特化和函数模板特化

#include <iostream>

using namespace std;

template<class T>
bool isEqual(T& left, T& right)
{
	return (left == right) ? 1 : 0;
}

int main()
{
	char* p1 = "Hello";
	char* p2 = "World";

	cout << isEqual(p1, p2) << endl;
	system("pause");
	return 0;
}

2.1、函数模板的特化

函数模板特化的步骤
1、必须先有一个函数模板
2、template<> 函数返回值 需要特化的函数名<需要特化的类型>(参数列表)
3、函数的形参列表必须和需要特化的类型一致

#include <iostream>

using namespace std;

template<class T>
bool isEqual(T& left, T& right)
{
	return (left == right) ? true : false;
}

template<>
bool isEqual<char*>(char*& left, char*& right)
{
	return (strcmp(left, right) == 0) ? true : false;
}

int main()
{
	char* p1 = "Hello";
	char* p2 = "World";
	char* p3 = "World";

	cout << isEqual(p1, p2) << endl;
	cout << isEqual(p2, p3) << endl;
	system("pause");
	return 0;
}

2.2、类模板的全特化

全特化是将模板参数列表中所有的参数都特化

#include <iostream>

using namespace std;

template<class T1, class T2>
class Data
{
public:
	Data()
	{
		cout << "Data()<T1, T2>" << endl;
	}
private:
	T1 m_d1;
	T2 m_d2;
};

template<>
class Data<int, char>
{
public:
	Data()
	{
		cout << "Data()<int, char>" << endl;
	}
private:
	int m_d1;
	char m_d2;
};

int main()
{
	Data<int, int> data1;
	Data<int, char> data2;
	system("pause");
	return 0;
}

2.3、类模板的偏特化

类模板的偏特化是指任何模板参数进一步进行条件限制的特化版本

类模板的偏特化分为两种
一种是部分特化:将模板参数的一部分特化
另外一种是参数的进一步限制:偏特化也可以是将模板参数进行更进一步的限制,而设计出的模板

#include <iostream>

using namespace std;

template<class t1, class t2>
class data
{
public:
	data()
	{
		cout << "data()<t1, t2>" << endl;
	}
private:
	t1 m_d1;
	t2 m_d2;
};

template<class t2>
class data<int, t2>
{
public:
	data()
	{
		cout << "data()<int, t2>" << endl;
	}
private:
	int m_d1;
	t2 m_d2;
};

template<class t1>
class data<t1, char>
{
public:
	data()
	{
		cout << "data()<t1, char>" << endl;
	}
private:
	t1 m_d1;
	char m_d2;
};

template<class t1, class t2>
class data<t1*, t2*>
{
public:
	data()
	{
		cout << "data()<t1*, t2*>" << endl;
	}
private:
	t1* m_d1;
	t2* m_d2;
};

template<class t1, class t2>
class data<t1&, t2&>
{
public:
	data(const t1& d1, const t2& d2)
		:m_d1(d1)
		, m_d2(d2)
	{
		cout << "data(t1&, t2&)" << endl;
	}
private:
	const t1& m_d1;
	const t2& m_d2;
};

int main()
{
	data<double, int> d1; // 调用特化的int版本
	data<int, double> d2; // 调用基础的模板
	data<int *, int*> d3; // 调用特化的指针版本
	data<int&, int&> d4(1, 2); // 调用特化的指针版本

	system("pause");
	return 0;
}

3、模板特化的应用,类型萃取

如何写一个通用的拷贝函数

#include <iostream>
#include <cstring>
#include <string>
#include <typeinfo>

using namespace std;

//类模板特化的应用:类型萃取

//使用memcpy进行拷贝(浅拷贝,对自定义类型无效)
template <class T>
void _copy1(T* dst, T* src, size_t size)
{
	memcpy(dst, src, sizeof(T*)*size);
}

//使用赋值方式拷贝(效率较低)
template<class T>
void _copy2(T* dst, T* src, size_t size)
{
	for (size_t i = 0; i < size; i++)
	{
		dst[i] = src[i];
	}
}

//增加bool类型区分自定义类型和内置类型
template<class T>
void _copy3(T* dst, T* src, size_t size, bool IsPODType)
{
	if (IsPODType)
	{
		memcpy(dst, src, sizeof(T*)*size);
	}
	else
	{
		for (size_t i = 0; i < size; i++)
		{
			dst[i] = src[i];
		}
	}
}

//使用函数区分内置类型和自定义类型
bool IsPODType(const char* strType)
{
	const char* arrType[] = { "char", "short", "int", "long", "long long", "float", "double", "long double" };
	for (size_t i = 0; i < sizeof(arrType) / sizeof(arrType[0]); i++)
	{
		if (!strcmp(strType, arrType[i]))
		{
			return true;
		}
	}
	return false;
}

template<class T>
void _copy4(T* dst, T* src, size_t size)
{
	if (IsPODType(typeid(T).name()))
	{
		memcpy(dst, src, sizeof(T*)*size);
	}
	else
	{
		for (size_t i = 0; i < size; i++)
		{
			dst[i] = src[i];
		}
	}
}

int main()
{
	string s1[3] = { "11", "22", "33" };
	string s2[3];

	_copy1(s2, s1, 3);
	_copy2(s2, s1, 3);
	_copy3(s2, s1, 3, true);
	_copy3(s2, s1, 3, false);
	_copy4(s2, s1, 3);
	system("pause");
	return 0;
}
#include <iostream>

using namespace std;

//代表内置类型
class TrueType
{
public:
	static bool Get()
	{
		return true;
	}
};

//代表自定义类型
class FalseType
{
public:
	static bool Get()
	{
		return false;
	}
};

template<class T>
class TypeTraits
{
public:
	typedef FalseType IsPODType;
};

template<>
class TypeTraits<char>
{
public:
	typedef TrueType IsPODType;
};

template<>
class TypeTraits<short>
{
public:
	typedef TrueType IsPODType;
};

template<>
class TypeTraits<int>
{
public:
	typedef TrueType IsPODType;
};

template<>
class TypeTraits<long>
{
public:
	typedef TrueType IsPODType;
};

template<>
class TypeTraits<long long>
{
public:
	typedef TrueType IsPODType;
};

template<>
class TypeTraits<float>
{
public:
	typedef TrueType IsPODType;
};

template<>
class TypeTraits<double>
{
public:
	typedef TrueType IsPODType;
};

template<>
class TypeTraits<long double>
{
public:
	typedef TrueType IsPODType;
};

template<class T>
void _copy(T* dst, T* src, size_t size)
{
	if (TypeTraits<T>::IsPODType::Get())
	{
		memcpy(dst, src, sizeof(T) * size);
	}
	else
	{
		for (size_t i = 0; i < size; i++)
		{
			dst[i] = src[i];
		}
	}
}

int main()
{
	int a1[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
	int a2[10];

	_copy(a2, a1, 10);

	string s1[] = { "111", "222", "333", "444" };
	string s2[4];
	_copy(s2, s1, 4);
	system("pause");
	return 0;
}

4、模板的分离编译

分离编译:一个程序或者项目由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有的文件链接起来,形成单一的可执行文件的过程

模板的分离编译指的是将模板的声明和定义分离开,头文件中声明,源文件中定义

a.h

#include <iostream>

using namespace std;

template<class T>
T Add(const T& left, const T& right);

a.cpp

#include "a.h"

using namespace std;

template<class T>
T Add(const T& left, const T& right)
{
	return left + right;
}

int main()
{
	cout << Add(1, 2) << endl;
	cout << Add(2.2, 3.3) << endl;
	system("pause");
	return 0;
}

5、模板的优缺点

优点:
1、模板复用了代码,节省资源,更快的迭代开发
2、增强了代码的复用性
缺点:
1、模板会导致代码膨胀
2、出现模板编译错误,不易定位错误信息

发布了117 篇原创文章 · 获赞 48 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/gp1330782530/article/details/105539010