C++模板编程与泛型编程之类模板、变量模板、别名模板(一)
发布日期:2021-05-07 15:12:22 浏览次数:15 分类:技术文章

本文共 3012 字,大约阅读时间需要 10 分钟。

类模板的基本范例和模板参数的推断

  • 类模板

    • 产生类的模具,通过给定的模板参数,生成具体的类,也就是实例化一个特定的类。
    • 例如vector<int>,引入类模板的目的,减少代码冗余

  • 基本范例
    •  myvector可以称为类名或者类模板
    • myvector<T>可以称为类型名(myvector后面带了尖括号,表示的就是 一个具体类型了)
  • 类模板定义
template 
//T是类型模板参数,表示myvector这个容器所保存的元素类型class myvector //myvector可以称为类名或者类模板 , myvector
可以称为类型名(myvector后面带了尖括号,表示的就是 一个具体类型了){public: typedef T* myiterator; //迭代器public: myvector(); //构造函数 //myvector& operator=(const myvector&); //赋值运算符重载 myvector
& operator=(const myvector&); //赋值运算符重载public: void myfunc() { cout << "myfunc()被调用" << endl; } static void mystaticfunc() { cout << "mystaticfunc()被调用" << endl; }public: //迭代器接口 myiterator mybegin(); //迭代器起始位置 myiterator myend(); //迭代器结束位置};
  • 类模板实现
template 
myvector
::myvector() //类外构造函数的实现{}
  • 类模板调用
myvector
tmpvec; //T被替换成了inttmpvec.myfunc(); //调用普通成员函数

  • 类模板中,只有被调用的成员函数(包括静态成员函数),编译器才会产生出这些函数的实例化代码

案例1:执行调用

myvector
tmpvec; //T被替换成了inttmpvec.myfunc(); //调用普通成员函数
  • 验证:
    • 将源文件编译生成 .obj 文件,然后利用dumpbin反汇编

  • 查看结果


案例2:不执行调用

myvector
tmpvec; //T被替换成了int//tmpvec.myfunc(); //调用普通成员函数
  • 验证:
    • 将源文件编译生成 .obj 文件,然后利用dumpbin反汇编

  • 查看结果


模板参数的推断

  • C++17中,类模板的类型模板参数也能推断了。
    • 在上面案例中加入带参构造函数代码,如下
template 
class myvector {public: myvector(); //构造函数 myvector(T tmpt) { }}
  • 调用时,不指定类型,由编译器自动推导
myvector tmpvec2(12); //无需指定模板参数了//不用写成//myvector
tmpvec2(12); tmpvec2.myfunc(); //调用类模板中的普通成员函数

推断指南(deduction guide)概要了解(引导编译器推断

  • c++17新概念:主要用来在推断类模板参数时提供推断指引。

  • 隐式的推断指南

    • 针对类模板A的每个构造函数都有一个隐式的模板参数推断机制存在,这个机制,被称为隐式的推断指南
template
struct A{ A(T val1, T val2) { cout << "A::A(T val1,T val2)执行了!" << endl; } A(T val) { cout << "A::A(T val)执行了!" << endl; }};
  • 调用
//A
aobj1(15, 16);A aobj1(15, 16); //A
A aobj2(12.8); //A

  • 推断指南解析:
    • 推断指南样式如下:
template
A(T,T)->A
;
  • 出现 -> 左侧部分内容或者形式时,请推断成 -> 右侧的类型。
  • 右侧类型也被称为“指南类型”
    • -> 左侧部分:该推断指南所对应的构造函数的函数声明,多个参数之间用,分隔。
    • -> 右侧部分类模板名,接着一个尖括号,尖括号中是模板参数名
  • A(T,T)->A<T> 的含义
    • 当用调用带两个参数的构造函数通过类模板A创建相关对象时,请用所提供的构造函数的实参来推断类模板A的模板参数类型
  • 一句话:推断指南的存在意义就是让编译器能够把模板参数的类型推断出来

  • 备注
    • 像这样是无法推断出A的模板参数,报错
A* aobj3 = NULL
  • 此时需要指定类型int
A
* aobj3 = NULL

自定义的推断指南

  • 在类定义后面进行自定义推断指南
template
struct A{ A(T val) { cout << "A::A(T val)执行了!" << endl; }};template
A(T)->A
;
  • 调用结果如下:
A aobj2(13.14); //A

  • 没有构造函数,就没有隐式地推断指南
template
struct B{ T m_b;};
  • 此时必须指定类型
::B
bobj1; //需要明确指定模板参数类型::B
bobj2{15}; //可以用初始化列表的方式来定义对象bobj2,成员变量m_b=15。

  • 在没有构造函数,就没有隐式地推断指南的情况下指定推断指南
template
struct B{ T m_b;};template
B(T)->B
;
  • 此时能推导出类型,如下
B bobj3{ 15 };
  • B bobj3{ 15 }不报错的原因
    • 类B是聚合类。 是可以通过 {} 初始化的
    • B bobj3{ 15 }这种形式正好就相当于调用了类模板B的带一个参数(15)的构造函数,尽管类模板B中实际并不存在构造函数。
    • 因为 template<typename T>   B(T) -> B<T>;
      • 推断指南的存在,当调用了类模板B带一个参数的构造函数时,推断出来的类型为B<T>,所以最终推断出来的类型为B<int>类型。

  • 如果需要针对两个参数,如下
B bobj4{ 15,20 };
  • 则需要增加两个参数的推导指南
template
struct B{ T m_b; T m_b2;};template
B(T)->B
;template
B(T,T)->B
;

 

上一篇:Go 变量的数据类型介绍及整型数据的使用
下一篇:Nginx学习笔记之网络收发与Nginx事件间的对应关系

发表评论

最新留言

感谢大佬
[***.8.128.20]2025年04月11日 18时20分01秒