STl-traits编程技巧

STl-traits编程技巧

无论是泛型思想或者是STL(标准库)的实际运用,迭代器(iterators)都扮演着重要的作用。STL的中心思想是:将容器和算法分开,彼此独立设计,最后再讲他们融合在一起。

容器和算法的泛型设计并不难,使用C++的类模板(class tempalte)和成员模板(function template)就能完成。

但要是将两者融合在一起,你还需要掌握一些其他的技巧,比如成员模板的参数推导,声明内置类型,还有最重要的偏特化技巧。


要提取变量的类型,我们先使用函数模板的参数推导

template< class T, class U>
void func_impl(T t, U u) {
   U temp;
}

template< class T>
void func(T t) {
	func_impl(t, *t);

}

这里是以func为对外的接口,实际操作在func_impl里面,这样的话可以由一个类型推导出多个相关的类型,还实现了较好的封装性。


因为模板(class template)只能推导参数,不能推导函数的返回类型,我们需要其他的技巧,声明内置类型就是一种不错的方法。

#include<iostream>
using namespace std;

template<class T>
class MyIter
{
public:
	typedef T value_type;//声明内嵌类型
	T *ptr;

	MyIter(T *p=0):ptr(p)
	{
	}

	T& operator*()const
	{
		return *ptr;
	}
};

template<class I>
typename I::value_type func(I ite)//这里I是MyIter, 返回类型是MyIter<T>里面T的类型,也就是int,有了typename和value_type,我们可以让返回值是任何类型都可以
{
	return *ite; //*ite指向的是int类型,根据T& operator*()const决定返回的类型
}



void main()
{
	MyIter<int> ite(new int(8));
	cout<<func(ite)<<endl;
}

typename的意思是告诉编译器这是一个类型,这样才能顺利通过编译


但是这样只能接受类,不能接受内置的类型,举个例子

//===============不支持原生指针的版本===
#include<iostream>
using namespace std;

template<class T>
class MyIter
{
public:
	typedef T value_type;//声明内嵌类型
	T *ptr;

	MyIter(T *p=0):ptr(p)
	{
	}

	T& operator*()const
	{
		return *ptr;
	}
};

template<class I>
typename I::value_type func(I ite)//这里I是MyIter, 返回类型是MyIter<T>里面T的类型,也就是int,有了typename和value_type,我们可以让返回值是任何类型都可以
{
	return *ite; //*ite指向的是int类型,根据T& operator*()const决定返回的类型
}



void main()
{
	int *p=new int(5);
	MyIter<int> ite(p);
	cout<<func(p)<<endl;//错误,因为p没有value_type类型,在func的返回处typename I::value_type出错,因为不存在
}


使用原生的指针就会出错。


这个时候我们需要偏特化技术

//=============================偏特化和traits提取特性

#include<iostream>
using namespace std;

template<class T>
class MyIter
{
public:
	typedef T value_type;//声明内嵌类型
	T *ptr;

	MyIter(T *p=0):ptr(p)
	{
	}

	T& operator*()const
	{
		return *ptr;
	}
};

template<class I>
struct iterator_trait{
	typedef typename I::value_type value_type;//提取出内嵌类型
};

//偏特化版本
template<class T>
struct iterator_trait<T*>
{
	typedef T value_type;//为了支持原生指针,即int等
};


template<class I>
typename iterator_trait<I>::value_type 
func(I ite)
{
	return *ite;
}


void main()
{
	int *p=new int(8);
	MyIter<int> ite(p);
	cout<<func(ite)<<endl;
}

这里的traits指的是就是提取去类里面的内置类型或者偏特化版本的内置类型


最后还是一个问题,还要设计一个指向常数对象的指针版本

//=======================带指向常对象的指针
#include<iostream>
using namespace std;

template<class T>
class MyIter
{
public:
	typedef T value_type;//声明内嵌类型
	T *ptr;

	MyIter(T *p=0):ptr(p)
	{
	}

	T& operator*()const
	{
		return *ptr;
	}
};

template<class I>
struct iterator_trait{
	typedef typename I::value_type value_type;//提取出内嵌类型
};

//偏特化版本
template<class T>
struct iterator_trait<T*>
{
	typedef T value_type;//为了支持原生指针,即int等
};

//针对指向常数对象的指针的偏特化版本
template<class T>
struct iterator_trait<const T*>
{
	typedef T value_type;
};



template<class I>
typename iterator_trait<I>::value_type 
func(I ite)
{
	return *ite;
}


void main()
{
	int *p=new int(8);
	const int c=7;
	const int*r=&c;
	MyIter<int> ite(p);
	cout<<func(r)<<endl;
}


你可能感兴趣的:(STl-traits编程技巧)