《C++Templates》筆記——3.非型別模板引數
阿新 • • 發佈:2018-12-04
對於函式模板和類模板,模板引數並不侷限於型別,普通值也可以作為模板引數。
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》