一、引入
你也可以为 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) 对象。