非型別函式模板引數
一、引入
你也可以為 function template 定義 nontype parameters。例如下面的 function template 定義了一組 函式,可以將引數 x 累加一個值(VAL)後傳回:
template <typename T, int VAL>
T addValue(T const& x) {
return x + VAL;
}
當我們需要把「函式」或「某種通用操作」作為引數傳遞時,這一類函式就很有用。例如使用STL(Standard Template Library,標準模板庫)時,你可以運用上述 function template 的例項(instantiation),將某值加到元素集內的每一個元素身上:
std::transform (source.begin(), source.end(), // 來源端起止位置
dest.begin(), // 目的端起始位置
addValue<int,5>); // 實際操作
最後一個自變數將 function template addValue()例項化了,使其操作成為「將5加進一個int 數 值中」。演算法transform()會對source 中的所有元素呼叫這個具現體(函式),然後把結果傳入 dest 中。
注意上述例子帶來的一個問題:addValue<int,5> 是個 function template 實體(instance),而我們知道,所謂「function templates 實體」被認為是命名了一組過載函式集,即使該函式集內可能只有一個函式。 根據目前標準, 編譯器無法藉助 「過載函式集」 來進行 template parameter 的推導。因此你不得不把 function template argument 強制轉型為精確型別:
std::transform (source.begin(), source.end(), // 來源端起止位置
dest.begin(), // 目的端起始位置
(int(*)(int const*)) addValue<int,5>); // 操作
C++ Standard 中 已 有一 個提案 要 求修正這種行為 ,使你不必 在這種場合強制 轉型。在尚未獲得修正之前,為保證程式的可移植性,你還是得像上面那麼做。
二、侷限性
注意,nontype template parameters 有某些侷限:通常來說它們只能是常數整數(constant integral values),包括 enum,或是「指向外部連結(external linkage)之物件」的指標。
以浮點數或 class-type objects 作為 nontype template parameters 是不可以的:
// 錯誤:浮點值不能作為 template parameters
template <double VAT>
double process (double v) {
return v * VAT;
}
// 錯誤:class objects 不能作為 template parameters
template <std::string name>
class MyClass {
...
};
不允許浮點字面常數 (floating-point literals) 或簡單的常量浮點表示式 (constant floating-point expressions)作為 template arguments,其實只是歷史因素,並非技術原因。由於並沒有什麼實作上的困難,或許將來C++會支援它。
由於字串字面常數(string literal)是一種採用內部連結(internal linkage)的物件,也就是說不同模組(modules)內的兩個同值的字串字面常數,其實是不同的物件,因此它們也不能被拿來作為 template arguments:
template <char const* name>
class MyClass {
...
};
// 錯誤:不能使用字串常量"hello"
MyClass<"hello"> x;
此外,全域性指標也不能被拿來作為 template arguments:
template <char const* name>
Class MyClass {
...
};
char const* s = "hello";
// 錯誤:s 是「指向內部連結(internal linkage)物件」的指標
MyClass<s> x;
但是你可以這麼寫:
template <char const* name>
Class MyClass {
...
};
extern char const s[] = "hello";
MyClass<s> x; // OK
全域性的 char array s 被初始化為 "hello",因此 s 是一個外部連結(external linkage) 物件。