前面说到了类模板可以定义非类型参数,其实函数模板也可以定义非类型参数。例如,下面的函数模板定义了一组用于增加特定值的函数:
template<typename T, int VAL>
T addValue(T const& x)
{
return x + VAL;
}
如果需要把函数或者操作用作参数的话,那么这类型函数就是相当有用的。譬如,借助于标准模板库(STL),你可以传递这个函数模板的实例化给集合中的每一个元素,让它们都增加一个整数值:
std::transform(source.begin(), //源集合的起点
source.end(), //源集合的终点
dest.begin(), //目标集合的起点
addValue<int, 5>); //操作(或者函数)
在上面的调用中,最后一个实参实例化了函数模板addValue(),它让int元素增加5.源集合source中的每一个元素都会调用实例化后的addValue函数,并把调用结果放入上档集合dest.
下面看具体的示例:
//addval.h
#ifndef ADDVAL_H
#define ADDVAL_H
#include <iostream>
template<typename T, int VAL>
T addValue(T const &x)
{
std::cout << "x====" << x << " VAL===" << VAL << std::endl;
return x + VAL;
}
#endif // ADDVAL_H
//addvaltest.cc
#include "addval.h"
#include <iostream>
//template<typename T, int VAL>
//T addValue(T const &x)
//{
// return x + VAL;
//}
void call_addValue()
{
addValue<int, 5>(42);
}
template <typename IT, typename OP>
void transform(IT beg, IT end, IT to, OP op)
{
while (beg != end){
*to++ = op(*beg++);
}
}
#if 1
int main()
{
call_addValue();
std::cout << "===================" << std::endl;
int m[] = {1, 2, 3, 4, 5, 6};
transform(m, m + 6, m, addValue<int, 5>);
for(int i = 0; i < 6; ++i)
std::cout << "m[" << i << "]=====" << m[i] << std::endl;
return 0;
}
#endif
非类型模板参数的限制
非类型模板参数是有限制的,通常而言,它们可以是常整数(包括枚举值)或都指向外部链接对象的指针。
浮点数和类对象(class-type)是不允许作为非类型模板参数的:
template<double VAT> //ERROR:浮点数不能作为非类型模板参数
double process(double v)
{
return v * VAT;
}
template<std::string name> //ERROR:类对象不能作为非类型模板参数
class MyClass {
...
};
之所以不能使用浮点数(包括简单的常量浮点表达式)作为模板实参是有历史原因的。然而,该特性的实现并不存在很大的技术障碍;因此,将来的C++版本可能会支持这个特性。由于字符串文字是内部链接对象(因为两个具有相同名称但处于不同模块的字符串,是两个完全不同的对象),所以你不能使用它们来作为模板实参:
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"初始化,是一个外部链接对象。