C++模板技术和STL实战开发(4)——STL实用编程技术(4)——traits技术

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技术也是泛型的基石

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值