【c++】模板进阶
代码语言:javascriptAI代码解释在这里插入图片描述。
·
- 如 size_t,int,char等。一般使用的是 size_t。
代码语言:javascript
AI代码解释
//#define N 10
template<class T, size_t N>
class Stack
{
private:
T _a[N];//vector的内存是在堆上申请,它是动态的,如果我们需要一个静态栈的话
size_t top;
size_t capacity;
};
int main()
{
Stack<int, 10> st1;
Stack<int, 1000> st2;
return 0;
}
- 如果我们使用c语言里的宏定义来控制一个静态栈的大小,那么每一个栈的大小都是固定的,为10个 T 类型所占字节;但如果我们使用非类型模板参数,我们就可以在创建栈的时候主动为它赋予一个适合的大小。
- 栈所占内存相比堆是非常少的,只有 1-8MB左右,而堆通常为GB级别,所以在创建静态栈等里面的一些静态数组的时候,内存不要申请过大,否则会发生栈溢出的现象。

在这里插入图片描述
1.2 array
- 相比于vector这种根据需要申请内存,只能访问已初始化的位置;静态数组则是先申请好内存,它能够访问范围内的所有位置。
- array是一个封装了固定大小数组的容器,使用方法跟上面的自定义栈差不多。
- 使用array需要包头文件array。
- 它不会初始化数据,数据还是随机值。
代码语言:javascript
AI代码解释
array<int, 10> a1;
int a2[10];
- 上面两者有什么不同?都不会初始化数据,都是申请一个10个int类型大小的静态数组。不同之处在于:array有严格的数组越界检查,而下面的越界检查是一种抽查(抽查相邻位置),而且只查写而不查读。
代码语言:javascript
AI代码解释
a1.fill(1);//可以使用fill进行初始化
二、模板的特化
模板的特化是在已有模板的基础之上另外进行改造,我们把这个基础模板叫做主模板,这个根据情况改造之后的模板就是特化模板。
- 主模板它适用于大多数类型,而特化模板只适用于特定类型,使用特化模板的就不会使用主模板,特化模板的优先级更高。
- 可以把主模板看作一个咖啡配方,这个咖啡配方适合大多数人;然后特化模板就是根据一些人的口味对咖啡配方进行微调,让这个咖啡的口味更适合这类人。而这类人有了更爱喝的咖啡之后自然就不会想去喝原来的咖啡了。
2.1 函数模板特化
- 函数模板是只有全特化,什么是全特化可以在下文进行了解。
- 函数模板特化格式:
代码语言:javascript
AI代码解释
template<>//表明这是一个特化版本
返回类型 主模板函数名<特化的类型>(主模板格式+特化类型 形参)
{
特化内容
}
- 看一个例子加深理解:
代码语言:javascript
AI代码解释
//主模板
template<class T>
void Less(const T& left, const T& right)
{
cout << "Less(const T& left, const T& right)" << endl;
}
//函数模板特化
//特化模板
template<>
void Less<double*>(double* const & left, double* const & right)
{
cout << "Less<double*>(double* const & left, double* const & right)" << endl;
}
int main()
{
Less(1, 2);
double n1 = 1.1, n2 = 2.2;
Less(&n1, &n2);
return 0;
}
执行结果:

在这里插入图片描述
- 对于double*类型,它调用的是特化后的模板,而不是原模板,正所谓有了更爱喝更适合的咖啡之后就不会去喝原来的咖啡了。
- 一个易错点:double* const & left 里的const 要在 * 的右边。这是因为 const 修饰的应该是(double*类型)引用本身,而不是指针所指向的值。否则特化不上。
- const 在 * 的左边,修饰指针所指向的内容,指针所指向的内容不能更改。
- const 在 * 的右边,修饰指针本身,指针本身不能够修改。
2.2 类模板特化
1. 全特化
全特化就是把模板里的模板参数全部给特化掉,换成具体的类型。比如上面的函数模板特化就是这样。
例子:
代码语言:javascript
AI代码解释
//主类模板
template<class T1, class T2>
class Date
{
public:
Date()
{
cout << "Date<T1, T2>" << endl;
}
private:
T1 _d1;
T2 _d2;
};
//特化类模板
template<>
class Date<int, char>
{
public:
Date()
{
cout << "Date<int, char>" << endl;
}
private:
int _d1;
char _d2;
};
int main()
{
Date<int, int> d1;
Date<int, char> d2;
return 0;
}
执行结果:

在这里插入图片描述
- template<>绝对不能漏掉。
2. 偏特化
偏特化有两种,一种是模板参数只有一部分换成具体的类型,一种是不把它们换成具体类型,而是模式特化(比如添加修饰符*)。
2.1 部分参数特化(部分参数换成具体类型)
代码语言:javascript
AI代码解释
//主类模板
template<class T1, class T2>
class Data
{
public:
Data()
{
cout << "Date<T1, T2>" << endl;
}
private:
T1 _d1;
T2 _d2;
};
//第一类部分参数特化
//特化第二个模板参数
template<class T1>
class Data<T1, char>
{
public:
Data()
{
cout << "Date<T1, char>" << endl;
}
private:
T1 _d1;
char _d2;
};
//特化第一个模板参数
template<class T2>
class Data<char, T2>
{
public:
Data()
{
cout << "Date<T2, char>" << endl;
}
private:
char _d1;
T2 _d2;
};
- 特化模板声明的时候要把没有特化的模板参数放在template<>里面,像是template<class T1>与template<class T2>。
- 类名后面跟参数模式,特化的把特化后的具体类型写上,没有进行特化的写原来的模板参数名。
更多推荐
所有评论(0)