essay | tech | year-summary | about
日期:2020-06-11T00:00:00Z
在cpp中的模板,其实就类似于JAVA以及C#中的 <T> 类型.
对于 <T> 有比较深的认知的话,就会明白这东西是有多么的好用了。
在cpp中,由于是可以overload的,所以同名函数会被认为是不同的函数。
int compare(const string& a, const string& b){
if(a < b){
return -1;
}
if(b < a){
return 1;
}
return 0;
}
int compare(const double& a, const double& b){
if(a < b){
return -1;
}
if(b < a){
return 1;
}
return 0;
}
那事实上这个东西是可以进行共通化的。
template <typename T>
int compare(const T& a, const T& b){
if(a < b){
return -1;
}
if(b < a){
return 1;
}
return 0;
}
这个就是最基本的template了。
以关键字template开始,后面跟一个模板参数列表(template parameter list),这里面可以有一个逗号分隔的一个or多个的模板参数(template parameter)。
在实际应用中,编译器会自动判断传值的类型来进行传值。
compare(1, 0); // int, int
vector<int> v{1, 2, 3};
compare(v, v); // vector<int>, vector<int>
template <typename T> T foo(T* p){
T tmp = *p;
//...
return tmp;
}
// 以下含义完全相同
// 推荐使用typename
template<typename T, typename U> T calc(const T&, const U&);
template<class T, class U> T calc(const T&, const U&);
template<typename T, class U> T calc(const T&, const U&);
template<class T, typename U> T calc(const T&, const U&);
非类型参数(nontype parameter)。指的是一个值而不是一个类型。
template<unsigned int N, unsigned int M>
int compare(const char (&p1)[N], const char (&p2)[M]);
// 注意,这里是数组的by ref,不是pointer。
ATTENTION
在传递文字列的时候,编译器会自动在字符串末尾插入一个'\0'作为结尾。
所以会这样传输。
compare("hello", "pa");
int compare(const char (&p1)[6], const char (&p2)[3]);
非类型模板参数(template parameter)可以是整型,pointer或者引用。
非类型参数的实参(tempate argument)必须是常量表达式。
tempalte同样可以用于inline/constexpr函数。
template<typename T> inline T min(const T&, const T&);
ps: constexpr是常量表达式的函数的定义关键字
上面的代码中都是const类型。
除了少数不可以拷贝的类型(unique_ptr和IO类型等),大多数类型都是可以拷贝的。
不过通过添加const,让我们可以让不可以拷贝的类型也可以被传进来。
上述的代码只使用一种比较符号 <
之所以这样设计的原因是,这样这些类型只需要支持 <
即可,不需要支持 >
这样的细节会影响处理速度,而且我们在使用template的时候应当尽快尽可能的减少对于类型的要求。
模板编译的时候,并不会生成代码。
只有我们实例出某一个版本的模板的时候,模板才会生成相应的代码。
这一特性影响我们如何debug。
在编译期间,我们调用某一函数的时候,某一函数必须被定义。同样某一个类也是一样。然后,某一个类的成员函数并不需要被提前定义。
所以类定义和函数声明往往在头文件中,
而普通函数和类的成员函数是在源文件中的。
但是模板不一样,为了生成实例化版本,编译器需要掌握函数模板或类模板成员函数的定义,所以模板的头文件通常既包括声明也包括定义。
接下来的章节次序的会跟着书本继续介绍。