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

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

你可能感兴趣的:(模板Trait 技术与简述template 元编程)