今天,带来模版进阶的讲解。
主要讲解:
- 非类型模版参数
- 模版的特化
- 模版的分离编译
文中不足错漏之处望请斧正!
非类型模版参数
模版参数分为类型模版参数和非类型模版参数。
可以这么理解:前者是为了泛化类型,后者给定了实际类型,更像是给类模板所有实例用的一个常量。
也有这样的要求:浮点数、类对象以及字符串是不允许作为非类型模板参数的。基本上就是用整形家族来当非类型模版参数。
声明格式
template <整形 参数名 = 值>
class vector
{};
见见猪跑
template <class T, size_t N = 10>
class vector
{
public:
private:
T _arr[N]; //大小是静态的数组
};
模版的特化
模版的特化就是模板的特殊实例。
为什么
模板再神通广大也并不能用在所有场景吧?总有那么几个特殊场景。
我们只能像以前那样单独写了吗?单独写可以,但也能用模版的特化解决
怎么玩
函数模版的特化
template<class T>
返回值类型 函数模版名(参数列表)
template<>
返回值类型 特化的函数名<要特化的类型>(参数列表)
见见猪跑
struct test {
int _i = 1;
};
template<class T>
int toInt(T input) {
cout << "int toInt(T input)" << endl;
return (int) input;
}
template<>
int toInt<test>(test input) {
cout << "int toInt<test>(test input)" << endl;
return input._i;
}
int main() {
test t;
char ch = 'a';
toInt(t);
toInt(ch);
return 0;
}
int toInt<test>(test input)
int toInt(T input)
注意:特化出的实例参数列表必须和模板完全相同。
不过,为了简单方便,遇到函数模版的特殊场景会直接单独提供,这样简单清晰。
类模板的特化
全特化
template<class T1, class T2>
class test {
public:
test() {
cout << "template<class T1, class T2> class test " << endl;
}
T1 _t1;
T2 _t2;
};
template<>
class test<int, double> {
public:
test() {
cout << "template<> class test<int, double>" << endl;
}
int _t1;
double _t2;
};
int main() {
test<char, int> t1;
test<int, double> t2;
return 0;
}
template<class T1, class T2> class test
template<> class test<int, double>
半特化(偏特化)
目的1:将参数特化
template<class T1, class T2>
class test {
public:
test() {
cout << "template<class T1, class T2> class test " << endl;
}
T1 _t1;
T2 _t2;
};
template<class T1>
class test<T1, int> {
public:
test() {
cout << "template<class T1> class test<T1, int>" << endl;
}
T1 _t1;
int _t2;
};
int main() {
test<char, char> t1;
test<char, int> t2; //第二个模版参数传了int,就走了特化
return 0;
}
template<class T1, class T2> class test
template<class T1> class test<T1, int>
目的2:对参数进一步限制
template<class T1, class T2>
class test {
public:
test() {
cout << "template<class T1, class T2> class test " << endl;
}
T1 _t1;
T2 _t2;
};
template<class T1, class T2>
class test<T1 *, T2 *> {
public:
test() {
cout << "template<class T1, class T2> class test<T1*, T2*>" << endl;
}
};
template<class T1, class T2> class test
template<class T1, class T2> class test<T1*, T2*>
模版的分离编译
核心结论
模版不可以分离编译。
为什么
假如我们分离成这样:
- add.h
- main.cpp
add.h中有类模版,main.cpp中用类模板实例出类型,再用类型实例出对象,调用对象的成员函数。
- 对象的成员函数对main来说是外部符号,等后续链接
- 类模板的成员函数是在调用的时候才实例
即,模板处不知道有人调用就没实例成员函数 && 调用处默认认为外部符号都能直接链接使用 = 链接一个根本没实例出来的函数 = 链接错误。
解决办法
- 声明定义不分离
- 调用处显式实例化类模板的成员函数
// stack.cpp
#include "stack.h"
template<class T>
void Stack<T>::push(const T& data)
{
_a[_size++] = data;
}
template<class T>
void Stack<T>::print()
{
for(int i = 0; i<_size; i++)
{
cout << _a[i] << ' ';
} cout << endl;
}
template class Stack<int>;//在最下面实例化才能实例化到全部模版(顺序编译)
:1
今天的分享就到这里了,感谢您能看到这里。
这里是培根的blog,期待与你共同进步!