模板参数并不局限于类型,普通值也可以作为模板参数。
非类型的类模板参数
template <typename T, int MAXSIZE>
class Stack
{
private:
T elems[MAXSIZE];
int numElems;
public:
bool full() const
{
return numElems == MAXSIZE;
}
};
非类型的函数模板参数
template <typename T, int VAL>
T addValue(T const &x)
{
return x + VAL;
}
非类型模板参数的限制
只有长整数(包括枚举)和指向外部链接对象的指针可以作为非模板参数,浮点数和类对象不允许。
和非类型模板实参相关的编译问题
基本数据类型const全局变量:
// ModuleA.h
template <int i>
void func_int()
{
}
template <const int *p>
void func_pint()
{
}
// main.cpp
const int i = 5;
const int * const pi_1 = &i;
const int * pi_2 = &i;
int main()
{
func_int<i>(); // const类型,编译期值确定
func_int<&i>(); // 全局变量,编译期地址确定
func_pint<pi_1>(); // error
func_pint<pi_2>(); // error
}
基本数据类型非const全局变量:
// ModuleA.h
template <int i>
void func_int()
{
}
template <int *p>
void func_pint()
{
}
// main.cpp
int i = 5;
int * const pi_1 = &i;
int * pi_2 = &i;
int main()
{
func_int<i>(); // error
func_pint<&i>(); // 全局变量,编译期地址确定
func_pint<pi_1>(); // error
func_pint<pi_2>(); // error
}
基本数据类型const局部变量:
// ModuleA.h
template <int i>
void func_int()
{
}
template <const int *p>
void func_pint()
{
}
// main.cpp
int main()
{
const int i = 5;
const int * const pi_1 = &i;
const int * pi_2 = &i;
func_int<i>(); // const变量,编译期值确定
func_int<&i>(); // error
func_pint<pi_1>(); // error
func_pint<pi_2>(); // error
}
基本数据类型非const局部变量:
// ModuleA.h
template <int i>
void func_int()
{
}
template <int *p>
void func_pint()
{
}
// main.cpp
int main()
{
int i = 5;
int * const pi_1 = &i;
int * pi_2 = &i;
func_int<i>(); // error
func_pint<&i>(); // error
func_pint<pi_1>(); // error
func_pint<pi_2>(); // error
}
小结:模板实际上是一种编译期多态,需要在编译期根据模板参数匹配模板实例。所以对于使用值类型模板参数的模板,使用时传递的模板实参必须是在编译期可以确定值和类型的。但是,对于指针,只能直接传参(在传参地方用&运算符取地址),不能间接传参(先取地址赋值给指针变量,再用指针变量做传参)。。。。知识盲区+_+
传参 | 直接类型 | 指针(&) | 指针变量 | const指针变量 |
---|---|---|---|---|
全局const int | 1 | 1 | 0 | 0 |
全局非const int | 0 | 1 | 0 | 0 |
局部const int | 1 | 0 | 0 | 0 |
局部非const int | 0 | 0 | 0 | 0 |