1. 程式人生 > >《C++Templates》筆記——3.非型別模板引數

《C++Templates》筆記——3.非型別模板引數

對於函式模板和類模板,模板引數並不侷限於型別普通值也可以作為模板引數。

1.非型別的類模板引數

#include <stdexcept>

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{
......
}

2.非型別的函式模板引數

你也可以為函式模板定義非型別引數。例如:

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 <iostream>
#include <vector>
#include <algorithm>

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;
}

執行結果:6 7 8

3.非型別模板引數的限制

非型別模板引數是有限制的,通常是常整數(包括列舉值)或者指向外部連結物件的指標
浮點數和類物件是不允許作為非型別模板引數

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"初始化,是一個外部連結物件。

4.總結

  • 模板引數不但可以是型別,也可以是值。
  • 非型別模板引數,不能使用浮點數、class類的物件和內部連結物件(例如string)作為實參。

詳情參考:《C++Templates》