模板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 - 博客园