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

时间: 2024-11-10 11:31:56

模板Trait 技术与简述template 元编程的相关文章

《Effective C++》:条款48:理解力template 元编程

Template metaprogramming(TMP,模板元编程)这是写template-based C++规划.编译过程.template metaprogramming随着C++写模板程序,化的过程.也就是说,TMP程序运行后,从templates详细化出来C++源代码.不再是模板了. TMP有两个作用,一是它让某些事更easy. 比如编写STL容器,使用模板,可是存放不论什么类型元素.二是将运行在运行期的某些工作转移到了编译期.另一个结果是使用TMP的C++程序可能在其它方面更高效:较

Effective C++ Item 48 认识 template 元编程

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 经验:Template metaprogramming (TMP, 模板元编程)可将工作由运行期移往编译期,因而得以实现早期错误侦测和更高的执行效率 示例1: template<typename IterT, typename DistT> void advance(IterT &iter, DistT d){ if(typeid(typename std::iterator_t

《Effective C++》:条款48:认识template元编程

Template metaprogramming(TMP,模板元编程)是编写template-based C++程序,编译的过程.template metaprogramming是用C++写的模板程序,编译器编译出具体化的过程.也就是说,TMP程序执行后,从templates具体化出来C++源码,不再是模板了. TMP有两个作用,一是它让某些事更容易.例如编写STL容器,使用模板,可是存放任何类型元素.二是将执行在运行期的某些工作转移到了编译期.还有一个结果是使用TMP的C++程序可能在其他方面

Effective C++ 条款48 认识template元编程

1. 模板元编程(template mataprogramming,TMP)是编写C++程序并执行于编译期的过程,"所谓template mataprogram(模板元程序),是以C++写成,执行于C++编译器内的程序.一旦TMP程序结束执行,其输出,也就是从templates具现出来的若干C++源码,便会一如往常地被编译". 2. 自从templates加入C++,TMP底层特性便被引进了,自从TMP于1990s初期被发现,TMP被日渐证明十分有用.TMP有两个伟大效力: 1). 它

C++11模版元编程

1.概述 模版元编程(template metaprogram)是C++中最复杂也是威力最强大的编程范式,它是一种可以创建和操纵程序的程序.模版元编程完全不同于普通的运行期程序,它很独特,因为模版元程序的执行完全是在编译期,并且模版元程序操纵的数据不能是运行时变量,只能是编译期常量,不可修改,另外它用到的语法元素也是相当有限,不能使用运行期的一些语法,比如if-else,for等语句都不能用.因此,模版元编程需要很多技巧,常常需要类型重定义.枚举常量.继承.模板偏特化等方法来配合,因此编写模版元

AutoSharedLibrary -- 基于模板元编程技术的跨平台C++动态链接加载库

基于模板元编程技术的跨平台C++动态链接加载库.通过模板技术,使用者仅需通过简单的宏,即可使编译器在编译期自动生成加载动态链接库导出符号的代码,无任何额外的运行时开销. ASL_LIBRARY_BEGIN(TestLib) ASL_SYMBOL(Proc_test1, test1, false) ASL_SYMBOL(Proc_test2, test2, true) ASL_LIBRARY_END() TestLib theLib; try { theLib.Load("./1.so"

AutoSharedLibrary -- 基于模板元编程技术的跨平台C++动态链接载入库

基于模板元编程技术的跨平台C++动态链接载入库.通过模板技术,使用者仅需通过简单的宏,就可以使编译器在编译期自己主动生成载入动态链接库导出符号的代码,无不论什么额外的执行时开销. extern "C" { typedef int(*Proc_fnTestDll)(); typedef const char* (*Proc_fnTestDll2)(const char*); } ASL_LIBRARY_BEGIN(Test) // 强制载入名为fnTestDll的接口,假设没有该接口.则

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

前言:毕设时在开源库上做的程序,但是源码看得很晕(当时导师告诉我这是模板元编程,可以不用太在乎),最近自己造轮子时想学习STL的源码,但也是一样的感觉,大致了解他这么做要干什么,但是不知道里面的机制.于是开始学习<C++模板元编程>,看完第二章对一些东西豁然开朗. PS:该书也有点老了,C++11标准还没出来,主要用的Boost库. Traits(特征) 说正题,在STL中经常可以见到后缀为traits的名字,比如经常用到的std::string,本质是类模板basic_string的第一个参

读书笔记 effective c++ Item 48 了解模板元编程

1. TMP是什么? 模板元编程(template metaprogramming TMP)是实现基于模板的C++程序的过程,它能够在编译期执行.你可以想一想:一个模板元程序是用C++实现的并且可以在C++编译器内部运行的一个程序,它的输出——从模板中实例化出来的C++源码片段——会像往常一样被编译. 2. 使用TMP的优势 如果这没有冲击到你,是因为你没有足够尽力去想. C++不是为了模板元编程而设计的,但是自从TMP早在1990年被发现之后,它就被证明是非常有用的,为了使TMP的使用更加容易