您的位置:首页 > 编程语言

模板Trait 技术与简述template 元编程

2016-05-08 20:41 302 查看

模板Trait 技术

想了好久都没有想到合适的例子,已是干脆直接使用[1]中的例子就好了。

STL 中引入了迭代器的概念。但是在本文中的例子不直接使用STL 的迭代器,而是写了一段很简短的代码,作为演示使用。

本例中的迭代器有三种:

Forward_Iter,只能向前进,也就是只能加非负数

Bidirectional_Iter,可以双向增减

Random_Iter,可以随意增减

*本例并没有沿用STL 中的名称,请注意区别

对于三种的迭代器的偏移,大概如下:

template<typename Iter, typename Dist>
void advance_test(Iter& iter, Dist dist)
{
if( iter is Random_Iter )
iter += dist;
else
{
if(d>=0) while(dist--) ++iter;
else while(dist++) --iter;
}
}


*advance_test 是为了避免与全局同名函数冲突

那么首先定义三种迭代器:

template<typename T>
class Iterator
{

T* pointer;

T* doPlus(const int i) const
{
return pointer + i;
}
public:
Iterator(T* inT): pointer(inT) {}
virtual ~Iterator() {}
T* get() const
{
return pointer;
}
operator T* () const {  return pointer; }
T operator * () const { return *pointer; }
friend T* operator + (const Iterator& it, const int i)
{
return it.doPlus(i);
}
friend T* operator + (const int i, const Iterator& it)
{
return it.doPlus(i);
}
friend T* operator - (const Iterator& it, const int i)
{
return it.doPlus(-i);
}
friend T* operator - (const int i, const Iterator& it)
{
return it.doPlus(-i);
}
};

template<typename T>
class Forward_Iter: public Iterator<T>
{
public:
Forward_Iter(T* inT):Iterator<T>(inT) {}
};

template<typename T>
class Bidirectional_Iter: public Iterator<T>
{
public:
Bidirectional_Iter(T* inT):Iterator<T>(inT) {}
};

template<typename T>
class Random_Iter: public Iterator<T>
{
public:
Random_Iter(T* inT):Iterator<T>(inT) {}
};


*为了简略起见,只是实现了部分的功能

定义有了,那么现在我们讨论如何去实现
advance
了。

迭代器是对原生指针的封装,那原生指针就属于
Random_Iter
了,那么我们希望
advance
也要能够支持原生指针的调用。

在这里我们利用函数的重载功能在进行不同类型的区分。

首先,我们定义不同的对应于各个迭代器的tag

struct Iterator_tag {};
struct Forward_Iter_tag : public Iterator_tag {};
struct Bidirectional_Iter_tag: public Iterator_tag {};
struct Random_Iter_tag: public Iterator_tag {};


然后定义一个统一的Iterator_traits 类,用以从迭代器中抽取有用的类型信息和兼容原生的指针:

template<typename Iter>
struct Iterator_traits
{
typedef typename Iter::iterator_category iterator_category;
};

//针对内置指针的偏特化
template<typename Iter>
struct Iterator_traits<Iter*>
{
typedef Random_Iter_tag iterator_category;
};


值得注意的是,要进行模板偏特化来兼容原生的指针。

然后在各个迭代器中加入最终的类型信息

template<typename T>
class Iterator
{
//...
public:
typedef Iterator_tag iterator_category;  //注意这里
//...
};

template<typename T>
class Forward_Iter: public Iterator<T>
{

public:
typedef Forward_Iter_tag iterator_category;
Forward_Iter(T* inT):Iterator<T>(inT) {}
};

template<typename T>
class Bidirectional_Iter: public Iterator<T>
{
public:
typedef Bidirectional_Iter_tag iterator_category;
Bidirectional_Iter(T* inT):Iterator<T>(inT) {}
};

template<typename T>
class Random_Iter: public Iterator<T>
{

public:
typedef Random_Iter_tag iterator_category;
Random_Iter(T* inT):Iterator<T>(inT) {}
};


然后我们定义了不同的重载函数,用来兼容各个迭代器:

template<typename Iter, typename Dist>
void doAdvance(Iter& iter, Dist dist, Forward_Iter_tag)
{
if(dist >=0 )
while(dist--) iter = iter + 1;
else
{
cerr<<"error!"<<endl;
abort();
}
}
template<typename Iter, typename Dist>
void doAdvance(Iter& iter, Dist dist, Bidirectional_Iter_tag)
{
if(dist >= 0)
while(dist--) iter = iter+1;
else
while(dist++) iter = iter - 1;
}
template<typename Iter, typename Dist>
void doAdvance(Iter& iter, Dist dist, Random_Iter_tag)
{
iter = iter + dist;
}
template<typename Iter, typename Dist>
void doAdvance(Iter& iter, Dist dist, Iterator_tag)
{
iter = iter + dist;
}


最后,就让
advance
调用
doAdvance
就可以。

template<typename Iter, typename Dist>
void advance_test(Iter& iter, Dist dist)
{
doAdvance(iter, dist,
typename Iterator_traits<Iter>::iterator_category()
);
}


到这里,功能就编写完成了。

测试使用的代码:

int a[1024];
for(int i=0;i<1024; ++i)
{
a[i] = i;
}
Forward_Iter<int> forward_iter(a);
forward_iter = forward_iter + 8;
cout<<*forward_iter<<endl;
Bidirectional_Iter<int> bd_iter(a);

bd_iter = bd_iter + 8;
advance_test(bd_iter, 8);
cout<<*bd_iter<<endl;
advance_test(bd_iter, -4);
cout<<*bd_iter<<endl;

int* b = a+9;
advance_test(b, 10);
cout<<*b<<endl;


输出:

8

16

12

19

关于template 元编程

引用[1]:

Template metaprogramming(TMP, 模板元编程),是编写template-based C++ 程序并执行于编译期的过程。

我觉得这个很有意思,[1]通过设计一个计算阶乘的例子来表现一下:

template<unsigned n>
struct Factorial
{
enum { value  = n*Factorial<n-1>::value };
};

template<>
struct Factorial<0>
{
enum{ value =  1 };
};


测试:

cout<<Factorial<7>::value<<endl;


[参考资料]

[1] Scott Meyers 著, 侯捷译. Effective C++ 中文版: 改善程序技术与设计思维的 55 个有效做法[M]. 电子工业出版社, 2011.

(条款47:请使用traits classes 表现类型信息;

条款48:认识template 元编程;)

[2]C++ traits学习笔记(一) - youthlion - 博客园
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: