Traits编程技法

照顺序,这次应该是迭代器Iterator的内容了,然而Iterator涉及到一个重要的技巧就是Traits编程技法。

一 获取Iterator的相应类型(associate type)

在使用Iterator时,可能需要知道它的相应类型,也就是Iterator指向的变量的类型,在C/C++语言中,如果要获取一个变量的大小可以使用sizeof()操作符。然而如果想要获取一个指针指向的变量类型该如何做呢,可惜它没有一个typeof()操作符供我们程序员使用。

利用template的引数/参数推导(argument deducation)是一个解决问题的好方法,仅将func函数作为一个包装,而把实际的操作放在一个函数func_impl里面完成。一旦func()函数被调用,编译器就自动进行引数推导,自动导出类型T。

#include 
using namespace std;

template
void func_imp(Point iter, T value)
{
	T tmp;     // 这里推导出了iter的数据类型
	tmp = value;
	cout << tmp << " in " << __FUNCTION__ << endl;
}

template
void func(Point iter)
{
	func_imp(iter, *iter);
}

int main()
{
	int *a = new int;
	*a = 10;
	func(a);

	return 0;
}

现在解决了从指针中获取原数据类型的方法,类型的的确确是获取到了,但要将类型作为一个函数的返回类型呢?有没有什么办法提前获取到类型呢,这就需要Traits编程技法了。

 Traits编程技法初见

采用nested type(巢状型别)似乎是个不错的注意,如下所示:

template
class Iterator {
public:
	typedef T value_type;
	T *m_ptr;
	Iterator(T *p = 0) : m_ptr(p) {}
	T& operator*()const { return *m_ptr;}	
};

template
typename I::value_type func2(I iter)
{
	return *iter;
}

int main()
{
	int *p = new int(8);
	Iterator iter(p);
	cout << func2(iter) << endl;
	delete p;

	return 0;
}

首先构建Iterator类,获取类型的方法和上文直接用两层函数的方法相似。这里func2函数的返回值前加上了一个typename,这是因为在template T实例化之前,编译器对T一无所知,并不知道Iterator::value_type代表的是一个函数,变量还是类型。关键字typename就是告诉编译器说这是一个类型,以使得编译通过。

看起来不错,但是这里还有一个隐晦的陷阱:并不是所有的迭代器都有value_type,编译器内嵌类型(原生指标)就没有,这样编译就不能通过,但是STL必须接受原生指标作为一种迭代器,这需要另外的技巧,它就是模板偏特化(template partial specialization)。
 

你可能感兴趣的:(计算机基础,代码精进之路)