C++模板技术和STL实战开发(4)——STL实用编程技术(4)——traits技术_c++模板技术与stl实战开发 网盘-程序员宅基地

技术标签: traits  C++的STL使用和源码学习  

1.数据类型表

是一种数据类型公开的能力,利用typedef这样的语句实现类型萃取器

模板名<模板实参>::类型名  变量名

这样使用的目的:

在不同模板之间,在类的外部形成数据访问能力

示例代码:

#include <iostream>
using namespace std;

template<typename T>
struct test
{
	typedef T value_type;
	typedef T& reference;
	typedef T* pointer;
};
int main()
{
	test<int>::value_type a = 100.9;
	cout << a << endl;

	test<double>::value_type b = 100.9;
	cout << b << endl;
}

上述代码内嵌了数据类型,从模板传入的类型衍生出了其对象相关类型的能力,外部的数据类型和内部传入的数据类型保持一致,保证了动态识别内部的数据类型

2.traits规范了多模块之间的类型一致

如果一个模板中,全部的成员都是public的,那么这个模板就是一个独立的数据类型表,用来规范数据

示例代码:

#include <iostream>
using namespace std;

//第一步:定义一个规范类模板类型表的基类模板
template<typename T,typename U>
class TypeTbl
{
public:
	typedef T value_type1;
	typedef T reference1;
	typedef U value_type2;
	typedef U reference2;
};
//第二步:凡是继承了这个类型表的模板,它的访问类型就被确定
template<typename T, typename U>
class Test :public TypeTbl<T, U>
{

};
int main()
{
	Test<int, double>::value_type1 a = 200;
	Test<int, double>::reference1 b = a;
	cout << a << endl;
	cout << b << endl;
}

在STL库中设计人员经常使用这样的技巧

Binary类中就使用了这样的技巧,对二元函数的形参类型进行了约束

示例代码:

#include <iostream>
using namespace std;

template <typename _A1,typename _A2,typename _R>
struct Binary
{
	typedef _A1 Arg1;
	typedef _A2 Arg2;
	typedef _R Ret;
};

//设计一个继承了binary接口的类模板
template <typename TR, typename T1, typename T2>
class Add :public Binary<TR, T1, T2>
{
public:
	TR bfun(const T1& x, const T2& y)const
	{
		return x + y;
	}
};

int main()
{
	double a = 100.09, b = 20.2;
	Add<double, double, double> addObj;
	cout << addObj.bfun(a,b)<< endl;
	//使用Arg1定义一个变量x
	typename Add<int, int, double>::Arg1 x = 1000;
	cout << x << endl;
}

分析:

因为Add包含了Binary的数据类型表,因此系统中的其他模块就可以使用Add::Arg1,Add::Arg2,Add::Ret这种方式和Add本身进行对接。

这种数据类型的抽象,达到了多个系统模块之间的类型统一

3.特化数据类型

示例代码:

class Test1
{
public:
	char compute(int x, double y)
	{
		return x;
	}
};

class Test2
{
public:
	double compute(double x, double y)
	{
		return x;
	}
};
//Test1和Test2都只有一个compute函数,而且函数逻辑也完全相同
//不同的仅仅是函数参数类型

//用模板来抽象Test1和Test2
template <typename Arg1,typename Arg2,typename Ret>
class Test
{
public:
	Ret compute(Arg1 x, Arg2 y)
	{
		return x;
	}
};

上述代码的分析:

           没有很好的复用已经设计好的函数,在Test的设计中已经侵入了Test1和Test2的设计,能够把Test写出来,是直到Test1和Test2是怎么实现的,也就是要直到它传入的模板参数(比如给调用Test1版本的话传入<int,double,char>,而在调用Test2的时候传入<double,double,double>),而我们现在就不想知道它的实现,直接传入<Test1>和<Test2>来调用它们各自的版本的函数,写法如下:

#include <iostream>
using namespace std;

class Test1;
class Test2;

//两个类模板规范一个统一的接口
template <typename T>
class TypeTbl
{

};

//特化模板
template <>
class TypeTbl<Test1>
{
public:
	typedef char ret_type;
	typedef int par1_type;
	typedef double par2_type;
};

template <>
class TypeTbl<Test2>
{
public:
	typedef double ret_type;
	typedef double par1_type;
	typedef double par2_type;
};

template<typename T>
class Test
{
public:
	typename TypeTbl<T>::ret_type compute(
		typename TypeTbl<T>::par1_type x,
		typename TypeTbl<T>::par2_type)
	{
		return x;
	}
};

int main()
{
	Test<Test1> t1;
	cout << t1.compute(65,6.18) << endl;
}

这样的写法使得类数据类型再做了一次抽象

4.指针的模板特化

泛型——一个重要的特征就是约定代码中的复杂数据类型的基本特征

比如说指向Student类的对象的指针pStudent和指向Teacher类的对象的指针pTeacher,两个没有任何关系,这两个要相互转化,就需要借助void*,如void*pTemp=pStudent,pTemp=pTeacher,在这个过程中,pTemp是不含有pStudent和pTeacher的信息的,这样会出现类型不安全问题:指针天生不具备向外提供数据类型的能力。指针仅仅是一个4个字节存储着地址信息的变量,它没有办法约束类型

如果想要对类型约束,我们需要对指针进行模板特化,这样衍生出符合接口定义的统一类型型别的别名

示例代码:

#include <iostream>
using namespace std;

template <typename T>
class Iterator_1
{
public:
	typedef T value_type;
	typedef value_type* pointer;
	typedef value_type& reference;
};

template <typename T>
class Iterator_2
{
public:
	typedef T value_type;
	typedef value_type* pointer;
	typedef value_type& reference;
};

template<typename T>
struct  Traits 
{
	
};

template<typename T>
struct  Traits<T*>
{
	typedef T value_type;
	typedef value_type* pointer;
	typedef value_type& reference;
};
int main()
{
	Iterator_1<int>::value_type t1= 100;
	cout << t1 << endl;
	Iterator_2<double>::value_type t2 = 100.5;
	cout << t2 << endl;

	Traits<double*>::value_type t3 = 100.09;
	cout << t3 << endl;
}

这样的写法对类型进行了规范,用户传进去什么类型,这种别名传出来的就是什么类型,比如Iterator_1中传入了int,实际最后t1也为int,Traits中传入了double,t3就是double类型

通过Traits的数据类型信息,可以有效的规范出类型型别统一,从而避免了类型转化问题

Traits技术也是泛型的基石

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_34805255/article/details/84311807

智能推荐

前端开发之vue-grid-layout的使用和实例-程序员宅基地

文章浏览阅读1.1w次,点赞7次,收藏34次。vue-grid-layout的使用、实例、遇到的问题和解决方案_vue-grid-layout

Power Apps-上传附件控件_powerapps点击按钮上传附件-程序员宅基地

文章浏览阅读218次。然后连接一个数据源,就会在下面自动产生一个添加附件的组件。把这个控件复制粘贴到页面里,就可以单独使用来上传了。插入一个“编辑”窗体。_powerapps点击按钮上传附件

C++ 面向对象(Object-Oriented)的特征 & 构造函数& 析构函数_"object(cnofd[\"ofdrender\"])十条"-程序员宅基地

文章浏览阅读264次。(1) Abstraction (抽象)(2) Polymorphism (多态)(3) Inheritance (继承)(4) Encapsulation (封装)_"object(cnofd[\"ofdrender\"])十条"

修改node_modules源码,并保存,使用patch-package打补丁,git提交代码后,所有人可以用到修改后的_修改 node_modules-程序员宅基地

文章浏览阅读133次。删除node_modules,重新npm install看是否成功。在 package.json 文件中的 scripts 中加入。修改你的第三方库的bug等。然后目录会多出一个目录文件。_修改 node_modules

【】kali--password:su的 Authentication failure问题,&sudo passwd root输入密码时Sorry, try again._password: su: authentication failure-程序员宅基地

文章浏览阅读883次。【代码】【】kali--password:su的 Authentication failure问题,&sudo passwd root输入密码时Sorry, try again._password: su: authentication failure

整理5个优秀的微信小程序开源项目_微信小程序开源模板-程序员宅基地

文章浏览阅读1w次,点赞13次,收藏97次。整理5个优秀的微信小程序开源项目。收集了微信小程序开发过程中会使用到的资料、问题以及第三方组件库。_微信小程序开源模板

随便推点

Centos7最简搭建NFS服务器_centos7 搭建nfs server-程序员宅基地

文章浏览阅读128次。Centos7最简搭建NFS服务器_centos7 搭建nfs server

Springboot整合Mybatis-Plus使用总结(mybatis 坑补充)_mybaitis-plus ruledataobjectattributemapper' and '-程序员宅基地

文章浏览阅读1.2k次,点赞2次,收藏3次。前言mybatis在持久层框架中还是比较火的,一般项目都是基于ssm。虽然mybatis可以直接在xml中通过SQL语句操作数据库,很是灵活。但正其操作都要通过SQL语句进行,就必须写大量的xml文件,很是麻烦。mybatis-plus就很好的解决了这个问题。..._mybaitis-plus ruledataobjectattributemapper' and 'com.picc.rule.management.d

EECE 1080C / Programming for ECESummer 2022 Laboratory 4: Global Functions Practice_eece1080c-程序员宅基地

文章浏览阅读325次。EECE 1080C / Programming for ECESummer 2022Laboratory 4: Global Functions PracticePlagiarism will not be tolerated:Topics covered:function creation and call statements (emphasis on global functions)Objective:To practice program development b_eece1080c

洛谷p4777 【模板】扩展中国剩余定理-程序员宅基地

文章浏览阅读53次。被同机房早就1年前就学过的东西我现在才学,wtcl。设要求的数为\(x\)。设当前处理到第\(k\)个同余式,设\(M = LCM ^ {k - 1} _ {i - 1}\) ,前\(k - 1\)个的通解就是\(x + i * M\)。那么其实第\(k\)个来说,其实就是求一个\(y\)使得\(x + y * M ≡ a_k(mod b_k)\)转化一下就是\(y * M ...

android 退出应用没有走ondestory方法,[Android基础论]为何Activity退出之后,系统没有调用onDestroy方法?...-程序员宅基地

文章浏览阅读1.3k次。首先,问题是如何出现的?晚上复查代码,发现一个activity没有调用自己的ondestroy方法我表示非常的费解,于是我检查了下代码。发现再finish代码之后接了如下代码finish();System.exit(0);//这就是罪魁祸首为什么这样写会出现问题System.exit(0);////看一下函数的原型public static void exit (int code)//Added ..._android 手动杀死app,activity不执行ondestroy

SylixOS快问快答_select函数 导致堆栈溢出 sylixos-程序员宅基地

文章浏览阅读894次。Q: SylixOS 版权是什么形式, 是否分为<开发版税>和<运行时版税>.A: SylixOS 是开源并免费的操作系统, 支持 BSD/GPL 协议(GPL 版本暂未确定). 没有任何的运行时版税. 您可以用她来做任何 您喜欢做的项目. 也可以修改 SylixOS 的源代码, 不需要支付任何费用. 当然笔者希望您可以将使用 SylixOS 开发的项目 (不需要开源)或对 SylixOS 源码的修改及时告知笔者.需要指出: SylixOS 本身仅是笔者用来提升自己水平而开发的_select函数 导致堆栈溢出 sylixos

推荐文章

热门文章

相关标签