目录
定义模板
【注意】模板参数列表不能为空。
template <typename T> //模板参数列表 int compare(const T &v1, const T &v2) { if (v1 < v2) return -1; if (v2 < v1) return 1; return 0; }
模板类型参数
typename和class的区别
二者其实是没有区别的,只是为了更加直观,才区分是typename环视class。当然,混用也是可以的:
template <typename T, class U>
calc (const T&, const U&);
费类型模板参数
1. 除了定义类型参数,还可以在模板中定义非类型参数,一个非类型参数表示一个值而非一个类型,我们通过一个特定的类型名而非关键字class或typename来指定非类型参数。
2. 一个非类型参数可以是一个整数,或者是一个指向对象或函数类型的指针或引用,绑定非类型整型参数的的实参必须是一个常量表达式,绑定到指针或引用非类型模板参数的实参,指针参数也可以用nullptr或一个值为0的常量表达式来实例化。
1 #include<iostream> 2 using namespace std; 3 template <class T, size_t N> 4 void array_init(T(&parm)[N]) 5 { 6 for (size_t i = 0; i != N; ++i) 7 { 8 parm[i] = i; 9 cout << parm[i] << " "; 10 } 11 cout << endl; 12 } 13 14 int main() 15 { 16 int x[4]; 17 double y[2]; 18 array_init(x); // array_init(int(&)[42] 19 array_init(y); // array_init(double(&)[10] 20 return 0; 21 }
运行结果:
非类型模板参数的限制:它可以是常整数(包括enum枚举类型)或者指向外部链接对象的指针。
1 template<double VAL> // ERROR: 浮点数不可作为非类型模板参数 2 double process(double v) 3 { 4 return v * VAL; 5 } 6 7 template<std::string name> // ERROR:类对象不能作为非类型模板参数 8 class MyClass 9 {}
稍作变通,我们即可使编译通过:
1 template<double* PVAL> 2 double process(const double& x) 3 { 4 return x * (*PVAL); 5 } 6 7 template<const char* name> 8 class MyClass 9 { 10 ... 11 }
这样可顺利通过编译,但如果想在当前文件中使用这两个模板,还需要修改:
1 double val = 10; 2 double res = process<&val>(20); // ERROR: 表达式必须含有常量值 3 4 MyClass<"hello"> x; // ERROR: 模板参数不能引用非外部实体 5 6 const char* s = "hello"; 7 MyClass<s> x; // ERROR: 表达式必须含有常量值
注意事项:非类型模板参数可以是指针,但该指针必须指向外部链接对象。
在A.cpp
中如何引用B.cpp
中的全局变量?回答:在A.hpp
中使用extern
关键字对外部变量加以引用。
1 // B.cpp 2 double val = 3.14159265; 3 char str[] = "hello"; 4 5 6 // A.hpp 7 extern double val; 8 extern char str[]; 9 10 11 // A.cpp 12 #include "A.hpp" 13 14 double res = process<&val>(10); 15 MyClass<str> x;