C++模板编程与泛型编程之类模板、变量模板、别名模板(一)

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

  • 类模板

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

  • 基本范例
    •  myvector可以称为类名或者类模板
    • myvector<T>可以称为类型名(myvector后面带了尖括号,表示的就是 一个具体类型了)
  • 类模板定义
template <typename T> //T是类型模板参数,表示myvector这个容器所保存的元素类型
class myvector  //myvector可以称为类名或者类模板 , myvector<T>可以称为类型名(myvector后面带了尖括号,表示的就是 一个具体类型了)
{
public:
	typedef T* myiterator; //迭代器

public:
	myvector();  //构造函数

	//myvector& operator=(const myvector&); //赋值运算符重载
	myvector<T>& operator=(const myvector&); //赋值运算符重载

public:
	void myfunc()
	{
		cout << "myfunc()被调用" << endl;
	}

	static void mystaticfunc()
	{
		cout << "mystaticfunc()被调用" << endl;
	}

public:
	//迭代器接口
	myiterator mybegin();  //迭代器起始位置
	myiterator myend();    //迭代器结束位置
};
  • 类模板实现
template <typename T>
myvector<T>::myvector() //类外构造函数的实现
{

}
  • 类模板调用
myvector<int> tmpvec; //T被替换成了int
tmpvec.myfunc();  //调用普通成员函数

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

案例1:执行调用

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

  • 查看结果


案例2:不执行调用

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

  • 查看结果


模板参数的推断

  • C++17中,类模板的类型模板参数也能推断了。
    • 在上面案例中加入带参构造函数代码,如下
template <typename T> 
class myvector  
{
public:
	myvector();  //构造函数

	myvector(T tmpt)
	{

	}
}
  • 调用时,不指定类型,由编译器自动推导
myvector tmpvec2(12); //无需指定模板参数了
//不用写成
//myvector<int> tmpvec2(12); 

tmpvec2.myfunc();  //调用类模板中的普通成员函数

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

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

  • 隐式的推断指南

    • 针对类模板A的每个构造函数都有一个隐式的模板参数推断机制存在,这个机制,被称为隐式的推断指南
template<typename T>
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<int> aobj1(15, 16);
A aobj1(15, 16); //A<int>
A aobj2(12.8); //A<double>

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

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

自定义的推断指南

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

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

  • 在没有构造函数,就没有隐式地推断指南的情况下指定推断指南
template<typename T>
struct B
{
	T m_b;
};
template<typename T>
B(T)->B<T>;
  • 此时能推导出类型,如下
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<typename T>
struct B
{
	T m_b;
	T m_b2;
};
template<typename T>
B(T)->B<T>;

template<typename T>
B(T,T)->B<T>;

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值