1. 程式人生 > >非型別函式模板引數

非型別函式模板引數

一、引入

你也可以為  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) 物件。