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

Posted 小键233

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了模板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 元编程的主要内容,如果未能解决你的问题,请参考以下文章

STL源码剖析——iterators与trait编程#1 尝试设计一个迭代器

初识C++模板元编程(Template Mega Programming)

C++ 模板元编程的最佳介绍? [关闭]

模板元编程 - 确定函数参数

模板元编程

模板元编程例子