C++之模版进阶篇(上)

简介: C++之模版进阶篇(上)

前言

在模版初阶我们学习了函数模版和类模版的相关知识,对模版有了一定的了解,接下来我们将对模版进行进一步的了解,话不多说,直接上货!!!

本节内容

1. 非类型模板参数

2. 类模板的特化

3. 模板的分离编译

1.非类型模版参数

模板参数分类类型形参与非类型形参

类型形参即:出现在模板参数列表中,跟在class或者typename之类的参数类型名称

非类型形参,就是 用一个常量作为类(函数)模板的一个参数 ,在类 ( 函数 ) 模板中可将该参数当成常量来使用

比如我们简单写一个静态栈,可以定义不同大小的栈,这里我们没有传默认参数,传也可以。

template<size_t N>
class Stack {
private:
    int _a[N];
    int _top;
};
int main() {
    Stack<5>s1;
    Stack<10>s2;
    return 0;
}

其实非类型形参在大小定义方面用的比较多,把大小当做常量。对于传参都传的是整数。

注意:

1. 浮点数、类对象以及字符串是不允许作为非类型模板参数的

2. 非类型的模板参数必须在编译期就能确认结果

在C++11版本的array用了 非类型的模板参数, 来代替静态数组。

#include <array>
#include <iostream>
using namespace std;
int main(){
 array<int, 10> a1;
 array<int, 100> a2;
int a3[10];
return 0;
}

那么用array定义数组的好处是什么呢,是数组初始化吗,当然不是。

相比较于int a3[10],其实array的好处是越界检查方面,array对于数组的读和写都会进行越界检查,而int a3[10],对于读不会检查,而写会检查,进行的是抽取,一般会在数组后面默认分配两个数据大小空间左右。

array<int, 10> a1;
 array<int, 100> a2;
// a1[100] = 3;
 int a3[10];
 cout << a3[100] << endl;
 a3[10] = 1;
// a3[12] = 1;

array底层访问是调用了一个函数进行实现,都会调用assert语句来判断。

template<class T, size_t N = 10>
class array
{
public:
  T& operator[](size_t index) { 
    assert(index < N);
    return _array[index];
  }
private:
  T _array[N];
  size_t _size;
};

其实对于数组的定义,在C++中我们采用vector来定义,可以进行初始化

vectorv(10,1);

但是如果要频繁的开设数组,其实array的效率可能要高些,因为array是在栈上开空间的,栈是向下生长的,vector是在堆上。

2.模版的特化

2.1概念

通常情况下, 使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些错误的结 ,需要特殊处理,比如:实现一个专门用来小于比较的函数模版

class Date {
public:
    Date(int year = 1, int month = 1, int day = 1)
        :_year(year),
        _month(month),
        _day(day)
    {}
    bool operator<(const Date& other) const {
        if (_year != other._year) return _year < other._year;
        if (_month != other._month) return _month < other._month;
        return _day < other._day;
    }
    /*
   friend ostream&operator<<(ostream& out, const Date& d) {
        out << d._year << "-" << d._month << "-" << d._day;
        return out;
    }*/
private:
    int _year;
    int _month;
    int _day;
};
template <class T>
bool Less(const T &left,const T& right) {
    return left < right;
}
int main() {
    cout << Less(1, 2) << endl; // 可以比较,结果正确
    
    Date d1(2024, 7, 9);
    Date d2(2024, 7, 8);
   cout << Less(d1, d2) << endl; // 可以比较,结果正确
   Date* p1 = &d1;
   Date* p2 = &d2;
   cout << Less(p1, p2) << endl; // 可以比较,结果错误
    return 0;
}

可以看到, Less 绝对多数情况下都可以正常比较,但是在特殊场景下就得到错误的结果。上述示例中, p1 指向的d1 显然大于 p2 指向的 d2 对象,但是 Less内部并没有比较p1p2指向的对象内容,而比较的是p1p2 指针的地址,这就无法达到预期而错误。

此时,就 需要对模板进行特化。即:在原模板类的基础上,针对特殊类型所进行特殊化的实现方式 。模板特化中分为函数模板特化 类模板特化

2.2函数模版特化

函数模板的特化步骤:

1. 必须要先有一个基础的函数模板

2. 关键字template后面接一对空的尖括号<>

3. 函数名后跟一对尖括号,尖括号中指定需要特化的类型

4. 函数形参表: 必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇怪的错误。

template <class T>
bool Less(const T &left,const T& right) {
    return left < right;
}
template<>
bool Less<Date*>(Date* const& left, Date* const& right)
{
  return *left < *right;
}
/*
template<>
bool Less<const Date*>(const Date* const& left, const Date* const& right)
{
    return *left < *right;
}
*/

注意:const要放在*之后,修饰的才是引用变量本身,放在*之前是修饰指向内容

非const特化

template <class T>
bool Less( T &left,T& right) {
    return left < right;
}
template<>
bool Less<Date*>(Date* &left, Date* &right)
{
  return *left < *right;
}

所以对于下面这段代码

Date * p1 = & d1 ;

Date * p2 = & d2 ;

cout << Less ( p1 , p2 ) << endl ; // 调用特化之后的版本,而不走模板生成了

注意:一般情况下如果函数模板遇到不能处理或者处理有误的类型,为了实现简单通常都是将该函数直接给 出。

bool Less(Date* left, Date* right)
{
 return *left < *right;
}

该种实现简单明了,代码的可读性高,容易书写,因为对于一些参数类型复杂的函数模板,特化时特别给出,因此函数模板不建议特化。


C++之模版进阶篇(下)https://developer.aliyun.com/article/1625011

目录
相关文章
|
7月前
|
存储 算法 编译器
【C++入门到精通】C++入门 —— 模版(template)
模板是C++中的一种编程工具,它允许使用通用代码来定义函数和类,以适应多种类型或值的需求,从而实现代码的复用和泛化。模板实质上是一种参数化的类型或值的规范。
91 0
|
7月前
|
算法 安全 编译器
【C++】从零开始认识泛型编程 — 模版
泛型编程是C++中十分关键的一环,泛型编程是C++编程中的一项强大功能,它通过模板提供了类型无关的代码,使得C++程序可以更加灵活和高效,极大的简便了我们编写代码的工作量。
81 3
|
2月前
|
Unix 编译器 Linux
C++之模版进阶篇(下)
C++之模版进阶篇(下)
49 0
|
2月前
|
编译器 C语言 C++
C++之模版初阶
C++之模版初阶
16 0
|
2月前
|
存储 编译器 C++
【C++模版初阶】——我与C++的不解之缘(七)
【C++模版初阶】——我与C++的不解之缘(七)
|
6月前
|
C++
C++中函数模版与类模版
C++中函数模版与类模版
56 4
|
7月前
|
算法 安全 编译器
C++:模版初阶 | STL简介
C++:模版初阶 | STL简介
|
7月前
|
算法 安全 编译器
C++:模版进阶 | Priority_queue的模拟实现
C++:模版进阶 | Priority_queue的模拟实现
|
7月前
|
机器学习/深度学习 存储 算法
C++ 模版函数介绍:介绍模版函数的基本概念、用法和作用
C++ 模版函数介绍:介绍模版函数的基本概念、用法和作用
72 1
|
7月前
|
编译器 C语言 C++
【C++初阶(九)】C++模版(初阶)----函数模版与类模版
【C++初阶(九)】C++模版(初阶)----函数模版与类模版
40 0