IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 模板进阶——C++ -> 正文阅读

[C++知识库]模板进阶——C++

1. 非类型模板参数

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

类型形参:
出现在模板参数列表中,跟在class或者typename之类的参数类型名称。
?
非类型形参:
就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用


```cpp
//定义一个静态数组的容器
#define N 100

template<class T>
class array
{
private:
T _a[N];
};

int main()
{
//类型实现了泛型编程
array<int> a1;    //100
array<double> a2; //1000

return 0;
}

?

但如果我们想让a1是100,a2是1000该怎么做?
再添加一个非类型模板参数——常量

template<class T, size_t N>
class array
{
private:
T _a[N];
};

int main()
{
//类型实现了泛型编程
array<int,100> a1;    //100
array<double,1000> a2; //1000

return 0;
}
模板参数和函数参数十分类似,我们还可以给参数缺省值
template<class T, size_t N = 10>
class array
{
private:
T _a[N];
};

int main()
{
array<int> a0;//10
array<int,100> a1;    //100
array<double,1000> a2; //1000

return 0;
}

非类型模板参数限制:只能用于整型
int char long double

?
?

array

容器里也有一个array
std::array
主要支持迭代器和[ ]
在C++11才增加的array

容器array与静态数组做对比
区别:关于越界的检查 读检查不到,写才检查得到,但实写的检查也是有限的(抽查)
一个是函数调用
一个是原生指针

int main()
{
array<int, 10> a1;  // C++11
int a2[10];         // C

cout << sizeof(a1) << endl;
cout << sizeof(a2) << endl;


  // 越界都能查出来 -- 函数调用
//a1[10];
a1[15] = 0;


 // 指针解引用 --  抽查是否越界,只针对越界写,越界读不检查
// a2[10];
// a2[10] = 1;
// a2[15] = 1;

return 0;
}

?
?

2. 模板的特化

模板的特殊化处理
通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些错误的结果,需要特殊处理

实现场景:
不仅函数模板可以特化,类模板也可以特化

?

函数模板的特化

struct Date
{
Date(int year, int month, int day)
:_year(year)
, _month(month)
, _day(day)
{}

bool operator>(const Date& d) const
{
if ((_year > d._year)
|| (_year == d._year && _month > d._month)
|| (_year == d._year && _month == d._month && _day > d._day))
{
return true;
}
else
{
return false;
}
}

bool operator<(const Date& d) const
{
if ((_year < d._year)
|| (_year == d._year && _month < d._month)
|| (_year == d._year && _month == d._month && _day < d._day))
{
return true;
}
else
{
return false;
}
}

int _year;
int _month;
int _day;
};


// 函数模板 -- 参数匹配
template<class T>
bool Greater(T left, T right)
{
return left > right;
}

// 特化--针对某些类型进行特殊化处理
//针对Data* C++不能比较类型
template<>
bool Greater<Date*>(Date* left, Date* right)
{
return *left > *right;
}

/
// 类模板
namespace haha
{
template<class T>
struct less
{
bool operator()(const T& x1, const T& x2) const
{
return x1 < x2;
}
};

 //特化
template<>
struct less<Date*>
{
bool operator()(Date* x1, Date* x2) const
{
return *x1 < *x2;
}
};
}

int main()
{
cout << Greater(1, 2) << endl;   // 可以比较,结果正确

Date d1(2022, 7, 7);
Date d2(2022, 7, 8);
cout << Greater(d1, d2) << endl;  // 可以比较,结果正确

Date* p1 = &d1;
Date* p2 = &d2;
cout << Greater(p1, p2) << endl;  // 可以比较,结果错误


haha::less<Date> lessFunc1;
cout << lessFunc1(d1, d2) << endl;//调用仿函数

haha::less<Date*> lessFunc2;
cout << lessFunc2(p1, p2) << endl;

std::priority_queue<Date, vector<Date>,haha::less<Date>> dq1;
std::priority_queue<Date*, vector<Date*>, haha::less<Date*>> dq2;
dq2.push(new Date(2022, 9, 27));
dq2.push(new Date(2022, 9, 25));
dq2.push(new Date(2022, 9, 28));
dq2.push(new Date(2022, 9, 29));


return 0;
}

不特化按指针比,特化了按指针指向的对象

?

类模板特化

全特化
偏特化
原则:有匹配就去走匹配的,没有的话将就一下也可以

template<class T1, class T2>
class Data
{
public:
Data() { cout << "Data<T1, T2>" << endl; }
private:
T1 _d1;
T2 _d2;
};

// 全特化
template<>
class Data<int, char>
{
public:
Data() { cout << "Data<int, char>" << endl; }
private:
/*int _d1;
char _d2;*/
};

// 偏特化——玩法很多
template <class T1>
class Data<T1, int>
{
public:
Data() { cout << "Data<T1, int>" << endl; }
private:
/*T1 _d1;
int _d2;*/
};
//以上两种是指定类型


// 偏特化
//只要两个都是指针,无论是什么类型的指针
template<class T1, class T2>
class Data<T1*,T2*>
{
public:
Data() { cout << "Data<T1*, T2*>" << endl; }
};

//模板参数还可以是引用 — — 迭代器
template<class T1, class T2>
class Data<T1&, T2&>
{
public:
Data() { cout << "Data<T1&, T2&>" << endl; }
};

//一个指针一个引用
template<class T1, class T2>
class Data<T1&, T2*>
{
public:
Data() { cout << "Data<T1&, T2*>" << endl; }
};

int main()
{
Data<int, int> d0;
Data<double, int> d1;

Data<int, char> d2;

Data<double, double> d3;
Data<double*, double*> d4;
Data<int*, char*> d5;
Data<int*, char> d6;

Data<int&, char&> d7;
Data<int&, double&> d8;
Data<int&, double*> d9;

return 0;
}

?
?

3.模板的分离编译

平时声明模板参数,可以用typename和class,没有区别
但是声明和变量分离时,用typename告诉编译器这是个类型,编译器分不清类型和变量

template<class T>
typename vector<T>::iterator vector<T>::insert(typename vector<T>::iterator pos, const T& x)
{
assert(pos >= _start);
assert(pos <= _finish);

if (_finish == _end_of_storage)
{
size_t len = pos - _start;
reserve(capacity() == 0 ? 4 : capacity() * 2);
pos = _start + len;
}

链接问题:有声明找不到定义
函数调用都会变成 call+一个地址
push_back();报错
原因:push_back没有被实例化

不用找
构造函数 size函数 operator[]是不会去链接
因为它们在vector.h中是有定义的
vector实例化时,这些成员函数也实例化,直接就有定义了,那么编译阶段就可以确定地址了

找不到
push_backinsert
这两个函数vector.h中只有声明没有定义,那么地址只能再链接阶段去确认。
报错证明链接阶段找不到。
T无法确定,所以没有实例化,那么push_back、insert就没有进符号表

·解决方案·:

  1. 模板的定义和声明不要分离到.h和.cpp (推荐
  2. 在.cpp里显示实例化 (麻烦,换个类型就要显示实例化一次

?
?

4. 模板总结

优点

  1. 模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生
  2. 增强了代码的灵活性

缺陷

  1. 模板会导致代码膨胀问题,也会导致编译时间变长
  2. 出现模板编译错误时,错误信息非常凌乱,不易定位错误
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-10-08 20:22:12  更:2022-10-08 20:26:07 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 7:50:36-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码