c++模板进阶——特化

模板参数:

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

template<class T,int n=10>  //T为模板参数,n为非模板参数
class aa
{
private:

	T[n] data;
};
 int main()
 {
	 aa<int, 100>;
	 return 0;
 }

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

特化:

函数模板的特化步骤:


1. 必须要先有一个基础的函数模板
2. 关键字template后面接一对空的尖括号<>
3. 函数名后跟一对尖括号,尖括号中指定需要特化的类型
4. 函数形参表: 必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇怪的错误。

前面三个点都非常简单,第四个点就非常让人头大。

比如我们我们要写这个模板的特化怎么写

template<class T>
void func(const T& data)//实际上换成指针为int* const data//是指针不能修改 
{
	cout << typeid(data).name() << endl;
}

我们要这样写:

template<>
void func<int*>(int* const& data)  //const放在*之后表示指针本身不能被修改
{
	cout << typeid(data).name() << endl;
}

如果对c++语法掌握不是很好的话一般都不知道怎么写。 一般用特化我们函数不会用特化。

类模板特化:

类模板的特化和函数模板的特化差不多

template<class T >
class cl
{
public:
	cl()
	{
		cout << "template<class T > " << endl;
	}
};

template<>//全特化
class cl<int*>
{
public:
	cl()
	{
		cout<<"template<>//全特化"<<endl;
	}
};

除了全特化还有偏特化

偏特化:

任何针对模版参数进一步进行条件限制设计的特化版本。比如对于以下模板类:

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

// 将第二个参数特化为int
template <class T1>
class Data<T1, int>
{
public:
	Data() { cout << "Data<T1, int>" << endl; }
private:
	T1 _d1;
	int _d2;
};

这样搞的模板就叫偏特化。

因此我们可以通过仿函数和偏特化的特性来写一个比大小功能。

比如我们在设计一个优先级队列时,就可以这样写:

template<class T>
struct less
{
	less() = default;

	bool operator()(const T& d1, const T& d2)
	{
		return d1 < d2;
	}
};
template<class T>
struct less<T*>
{
	less() = default;
	bool operator()(T* d1, T* d2)
	{
		return *d1 < *d2;
	}
};



template<class T>
struct mygreater
{
	mygreater()=default;
	bool operator()(const T& d1, const T& d2)
	{
		return d1 > d2;
	}
};
template<class T>
struct mygreater<T*>
{
	mygreater() = default;
	bool operator()(T* d1, T* d2)
	{
		return *d1 > *d2;
	}

};




template< class T, class Container = vector<T>,  class func=less<T>>
class priority_queue
{
public:
	priority_queue()=default;

	void push(const T& data)
	{
		_con.push_back(data);
		Adjust_Up(_con.size()-1);
	}

	void pop()
	{
		_con.erase(_con.begin());
		Adjust_Down(0);
	}

	T& top()
	{
		return _con[0];
	}

	bool empty()
	{
		return _con.empty();
	}

	//向下调整
	void Adjust_Down(size_t father)
	{
		func f1;
		size_t child= father * 2+1;
		while (child < _con.size())
		{
			if (child + 1 < _con.size() && f1(_con[child] , _con[child + 1]))
			{
				child++;
			}
			if (!f1(_con[child] , _con[father]))
			{
				swap(_con[child], _con[father]);
				father = child;
				child = father * 2 + 1;
			}
			else
			{
				break;
			}
		}
	}


	//向上调整
	void Adjust_Up(size_t child)
	{
		func f1;
		size_t father = (child - 1) / 2;
		while (child > 0)
		{
			if (!f1(_con[child] , _con[father]))
			{
				swap(_con[child], _con[father]);
				child = father;
				father = (child - 1) / 2;
			}
			else
			{
				break;
			}
		}
	}

private:
	Container _con;
};

对于向下调整,和向上调整的时候,我们就用仿函数,如果当我们传入的是指针他就会生成关于指针的比较的对象,如果不这样做,对象里的比较只能是具体的对象(内置类型,自定义类型),不能是指针。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值