C++进阶教程之模板3--一些知识的填充(霜之小刀 附视频)
来源:互联网 发布:java中scanner的作用 编辑:程序博客网 时间:2024/04/29 09:01
C++进阶教程之模板3--一些知识的填充(霜之小刀)
QQ:2279557541
Email:lihn1011@163.com
博客地址:http://blog.csdn.net/lihn1987
优酷主页:http://i.youku.com/shuangzhixiaodao
1. typename的另外一种用途
前面的几期内容中,我们知道了typename的一个功能,就是用于声明模板参数中的类型参数。比如
template<typename T>
void func(){
....
}
但是typename还有另外一种用途。用于定义后面跟着的是一个类型。
比如我们定义一个模板.
#include <vector>
template<typename T>
class TestClass
{
private:
T::iterator iter;
};
int main()
{
TestClass<std::vector<int>>a;
system("pause");
return 0;
}
我们想这个模板接受的模板参数都是标准库中的容器,然后在容易中定义一个容器的迭代器(iterator)类型的变量。
但是我们发现程序报错了。为何报错?
他把T::iterator看成了iterator是T的一个静态成员变量。。。。
那么怎样让编译器知道T::iterator是一种类型呢?就是在前面加一个typename告知编译器,后面跟着的是一个类型。
template<typename T>
class TestClass
{
private:
typename T::iterator iter;
};
int main()
{
TestClass<std::vector<int>>a;
system("pause");
return 0;
}
目前看到的这种情况是发生在成员变量的定义时,那要是在函数中定义依赖模板参数T的成员类型的变量会发生什么情况呢?
template<typename T>
class TestClass
{
public:
void function()
{
T::iterator pos;
}
private:
typename T::iterator iter;
};
int main()
{
TestClass<std::vector<int>>a;
a.function();
system("pause");
return 0;
}
我所使用的vs2015的编译器并没有报错。但是为了防止其他的一些编译器会报错,我们可以养成一种习惯,就是任何依赖传入模板参数的类型前都加一个typename。
2. 模板的模板参数
听着就有点绕,这一节也会比较绕。
比如我们写一个类,想用来封装一个标准库的容器。
我们期望的使用方式是这样的
MyClass<int, std::vector>
就是分装一个用std::vector<int>来存储数据的类型。
#include <iostream>
#include <string>
#include <vector>
#include <list>
template<typename T>
class MyList:public std::list<T>
{
};
template<typename T>
class MyVector :public std::vector<T>
{
};
template <typename T1,template<typename TMP>class T2>
class TestClass
{
private:
T2<T1>m_list;
};
int main()
{
TestClass<int,MyVector> a;
system("pause");
return 0;
}
首先代码中先写了两个模板类MyList与MyVector分别继承自std::list与std::vector,这里为什么要写这两个完全没有用单单是继承的模板类呢?
这个问题我们放到后面再讲,这里只需要把MyList当成std::list,把MyVector当成std::vector的功能即可。
然后看我们的TestClass,他的模板参数是这样定义的
template <typename T1,template<typename TMP>class T2>
其中第一个参数容易理解,但是第二个参数怎么理解呢?因为我们传入的不是一个固定的类型,而是一个模板类的名称,所以这里就要先声明一个模板类
template<typename TMP>class T2
这就是我们定义的模板类,其中T2就是我们那个模板类的名称,而TMP其实是完全没有用到的,可以省略因此我们这里可以吧这一行改为
template <typename T1,template<typename>class T2>
这就是模板的模板参数。
本来呢说到这其实就已经完了,但是我们看这段代码不觉得很别扭么?
为什么非要用MyList与MyVector???如果我们直接用标准库中的容器会如何?
于是我们把
TestClass<int,MyVector> a;
改为
TestClass<int,std::vector> a;
结果,编译器报错!!!!为何????
于是看一下std::vector的定义为
template<class _Ty,
class _Alloc =allocator<_Ty> >
class vector{
.....此处省略无数代码
}
原来他的模板定义不止有一个参数
于是我们修改下我们的TestClass
然后源代码变为:
#include <iostream>
#include <string>
#include <vector>
#include <list>
template <typename T1,template<typename TMP,typename _Alloc =std::allocator<TMP>>class T2>
class TestClass
{
private:
T2<T1>m_list;
};
int main()
{
TestClass<int,std::vector>a;
system("pause");
return 0;
}
这样貌似简介多了,再也没有中间的那个什么MyList,MyVector这种鬼了。但是我们看看模板参数这一行
template <typename T1,template<typename TMP,typename _Alloc =std::allocator<TMP>>class T2>
这个里面的TMP由于后面要用到,没法省略了,但是那个_Alloc貌似没啥用了啊,这个能省么???
尝试一下改为
template <typename T1,template<typename TMP,typename = std::allocator<TMP>>class T2>
没错!果然是可以省略的!
至此,我们的需求终于实现了,这一节的内容也就讲完了
3. 模板中字符串的推导
首先先看下面这个例子
template<typename T>
void func1(T a,T b)
{
std::cout << typeid(T).name()<< std::endl;
}
template<typename T>
void func2(T&a, T&b)
{
std::cout << typeid(T).name()<< std::endl;
}
int main()
{
func1("aaa","bbb");
func1("aaa","cccc");
func2("aaa","bbb");
//func2("aaa", "cccc");编译器报错
system("pause");
return 0;
}
输出为:
char const *
char const *
char const [4]
这种输出的原因是,当模板参数传入的类型不是引用时,数组会自动被推导为指针,而第二个模板由于函数模板由于传入的是引用,则使用了原来的数组类型,所以备注释报错的那一行中的”aaa”,”cccc”得类型分别是char const [4]和 char const[5]的类型。
这里多讲一点,字符串常量,也即是我们代码里直接写的”aaa”这种,其实编译器会将其识别为一个char const [4]的数组,而数组里的四个元素分别为字符’a’,’a’,’a’,’a’,’\0’
相关视频请在我的优酷主页中查找。
- C++进阶教程之模板3--一些知识的填充(霜之小刀 附视频)
- C++进阶教程之模板1--模板函数(霜之小刀 附视频)
- C++进阶教程之模板2--简单模板类(霜之小刀 附视频)
- 虚幻引擎4系列教程3(霜之小刀)(附视频)--游戏是需要逻辑的
- 虚幻引擎4系列教程2(霜之小刀)(附视频)--第一人称场景建模
- 虚幻引擎4系列教程2(霜之小刀)(附视频)--第一人称场景建模
- 虚幻引擎4系列教程1(霜之小刀)(附视频)--虚幻引擎4(UE4)安装教程
- 数据结构3----线性表中链式结构的其他几种实现(霜之小刀)
- 数据结构2----线性表顺序存储和链式存储的实现(霜之小刀)
- VS2015中STL源码解析1(霜之小刀)
- HTTP视频知识填充
- 嵌入式之C语言教程视频汇总
- Vim教程之进阶
- SQL注入之实践--初试小刀
- SQL注入之实践--初试小刀
- SQL注入之实践--初试小刀
- SUNWEN教程之----C#进阶3
- 关于模板的一些知识
- 【leetcode】203. Remove Linked List Elements
- window简单的命令
- Content Type working with Document Word
- VIJOS 1547 逆转,然后再见
- WSDL学习笔记
- C++进阶教程之模板3--一些知识的填充(霜之小刀 附视频)
- Android MVP模式
- nginx+tomcat7+redis实现tomcat集群session共享
- java NIO1 学习
- PHP使用hash_algos函数计算哈希值,之间的性能排序
- JAVAweb开发技术-------(五)XML技术
- 217. Contains Duplicate
- win10 破解-myeclipse10.7.1-存在问题及解决办法
- 【hdu】3277 Marriage Match III【最大流】