C++ 非类型的模板参数

对于函数模板和类模板,模板参数并不局限于类型普通值也可以作为模板参数

文章目录

  • 非类型的类模板参数
  • 非类型的函数模板参数
  • 非类型模板参数的限制
  • 总结

非类型的类模板参数

#include 

template <typename T, int MAXSIZE>
class Stack{
private:
	int elems[MAXSIZE];     //包含元素数组
	int numElems;           //元素的当前个数
public:
	Stack();                //构造函数
	void push(T const&);    //压入元素
	void pop();             //弹出元素
	T top() const;          //返回栈顶元素
	bool empty() const {    //返回栈是否为空
		rerurn numElems == 0;
	}
	bool full() const {     //返回栈是否已满
		return numElems == MAXSIZE;
	}
};

//构造函数
template <typename T, int MAXSIZE>
Stack<T, MAXSIZE>::Stack() : numElems(0)
{

}

//压入元素
template <typename T, int MAXSIZE>
void Stack<T, MAXSIZE>::push(T const& elem)
{
	if (numElems == MAXSIZE){
		trow std::out_of_range("Stack<>::push(): Stack is full!");
	}
	elems[numElems] = elem;  //附加元素
	++numElems;   //增加元素的个数
}

//弹出元素
template <typename T, int MAXSIZE>
void Stack<T, MAXSIZE>::pop()
{
	if (numElems <= 0){
		trow std::out_of_range("Stack<>::push(): empty Stack!");
	}
	--numElems;  //减少元素的个数
}

//返回栈顶元素
template <typename T, int MAXSIZE>
T Stack<T, MAXSIZE>::top() const 
{
	if (numElems <= 0){
		trow std::out_of_range("Stack<>::push(): empty Stack!");
	}
	return elems[numElems-1];  //返回最后一个元素
}

为了使用上述模板,必须同时指定元素的类型和个数(即栈的最大元素容量)。

Stack<int, 20> int20Stack;
Stack<int, 40> int40Stack;
Stack<std::string, 40> stringStack;

当然,上面的模板同样可以为模板参数设置缺省值

template <typename T = int, int MAXSIZE = 99>
class Stack{
......
}

非类型的函数模板参数

你也可以为函数模板定义非类型参数。例如:

template<typename T, int VAL>
T addValue(T const& x)
{
    return x + VAL;
}

如果需要把函数或者操作用作参数的话,这类函数就相当有用。借助于标准模板库(STL),可以传递这个函数模板的实例化给集中的每一个元素,让他们都增加一个整数值:

std::transform(source.begin(), source.end(),            //源集合的起点和终点   
                dest.begin(),                           //目标集合的起点    
                (int(*)(int const&))addValue<int, 5>;   //操作(或者函数)  

上面的调用,最后一个实参实例化的函数模板addValue(),它上int元素加5。源集合source中的每一个元素都会加5将结果存在目标集合中。下面是一个使用std::transform()函数的例子:

#include "Stack.hpp"
#include 
#include 
#include 

template<typename T, int VAL>
T addValue(T const& x)
{
	return x + VAL;
}

int main()
{
	std::vector<int> source;
	source.push_back(1);
	source.push_back(2);
	source.push_back(3);

	std::vector<int> dest;
	dest.resize(source.size()); //这一句不能少!!!
	
	std::transform(source.begin(), source.end(),            
		dest.begin(),                           
		(int(*)(int const&))addValue<int, 5>);
	for (int i = 0; i < dest.size(); i++)
	{
		std::cout << dest[i] << " ";
	}
	
	system("pause");
	return 0;
}

非类型模板参数的限制

非类型模板参数是有限制的,通常是常整数(包括枚举值)或者指向外部链接对象的指针。
浮点数类对象是不允许作为非类型模板参数:

template<double VAT>
double process(double v) //error:浮点数不能作为非类型模板参数
{
    return V * VAT;
}

template<string name>  //error:类对象不能作为非类型模板参数
class MyClass {
    ...
};

由于字符串文字是内部链接对象(因为两个具有相同名称但出于不同模块的字符串,是两个不同的对象),所以不能使用它们作为模板实参。

不能使用全局指针作为模板参数:

template<char const* name>
class MyClass {
    ...
};

char const s[] = "hello";
MyClass<s> x;   //s是一个指向内部链接对象的指针

但是我们可以这样来使用:

template<char const* name>
class MyClass {
    ...
};

extern char const s[] = "hello";
MyClass<s> x;  //OK

全局字符数组s由"hello"初始化,是一个外部链接对象。

总结

模板参数不但可以是类型,也可以是值。
非类型模板参数,不能使用浮点数、class类的对象和内部链接对象(例如string)作为实参。
详情参考:《C++Templates》

你可能感兴趣的:(C/C++)