注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

还东国的博客

行之苟有恒,久久自芬芳

 
 
 

日志

 
 

模板的特化和模板元编程  

2013-04-25 21:53:18|  分类: C++(VC)编程 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

模板的特化和模板元编程

模板的特化有以下几种:

1、  模板的全特化(全部特化):

主模板类:

template<typename T1, typename T2>

 class A{

 public:

     void Test(T1 a, T2 b)

{

         cout<<"a is  = "<<a<<endl;

         cout<<"b is = "<<b<<endl;

     }

 };

全特化:

template<>

class A<int, double>// 类型明确化,是个全特化类

{

     public:

     void Test(int a, double b)

{

         cout<<"int a is = "<<a<<endl;

         cout<<"double b is = "<<b<<endl;

     }

一个类被称为全特化类的条件:1.必须有一个主模板类   2.模板类型被全部明确化。

另外看3中,其实两者是一个东东。

在前面的“暇隙读书(5)——STL源码剖析之一模板的宏定义 ”中最后提到的模板元编程中的的数列计算其实也是全特化的一种形式。

2、  模板的偏特化(局部特化、部分特化):

偏特化也比较简单:

正常的一个模板类:

Templeate <typename T1,typename T2>

Struct   A

{

  Public:

    Void SetData(T1 t1,T2 t2);

};

Templeate<typename T2>

Struct  A<int,T2>

{

           Void SetData(int a,T2 t2);

};

3、  模板的显示特化:

In standardese, a full specialization is called an "explicit specialization."这句话的意思非常明显,显示特化和全特化是一回事儿。

在前面的模板的分享编译中提到过:

template <> struct hash1<char>           

{

       void operator()()

       {

              cout<<"hash<CHAR>"<<endl;

       }

};

注意:这个显示特化也必须有1中提到的主模板类,这里没写。

这个有一点需要说明,就是STL上定义的那个宏__STL_TEMPLATE_NULL,具体的大家可以看《STL源码剖析》第34页。也就是说有的编译器是不支持的,在VS2010中如果没有template <>会报一个错,指出 这个地方需要这个东西。

其实大家一看就明白,显示特化其实就是把模板具体定义成某种或几种类型,那么就可以直接使用了。

那这么做有什么用处呢?举个简单例子,比如你定义一个模板类,对其它所有的类型都执行返回true,唯有是char类型时返回false,那么这么做就有意义了。

explicit specialization显示实例化(应该叫显示特化或者全特化,叫显示实例化有误2016-04-28)一定要注意不能在头文件中进行,否则会报一个无法链接的错误.切切,切切.

函数模板是不能在头文件中,但类模板的特化要紧跟在主模板类后(无论在头还是在CPP),具体的可看“对特化的新的理解”2016-04-28

4、  一些有争议的:

// specialize for T*这种在源码剖析里归到了偏特化

template<class T>

class Compare<T*>

{

public:

    static bool IsEqual(const T* lh, const T* rh)

    {

        return Compare<T>::IsEqual(*lh, *rh);

    }

};

特化为另外一个类模板:

// specialize for vector<T>

template<class T>

class Compare<vector<T> >

{

public:

    static bool IsEqual(const vector<T>& lh, const vector<T>& rh)

    {

        if(lh.size() != rh.size()) return false;

        else

        {

            for(int i = 0; i < lh.size(); ++i)

            {

                if(lh[i] != rh[i]) return false;

            }

        }

        return true;

    }

};

混合型的:

template<typename T1, typename T2>

class X {...};

template<typename T>

class X<vector<T>, int&> {...}; //至于这里怎么都把T2搞没了变成只依赖一个模板参数T了的问题,大家别着急,我来告诉你个本质的东西,把我这么三点就可以了:1.模板参数个数一致;2.只要template <...>里面有东西不是<>,比如typename T,那么特化时就得用到T3.不进行任何对模板参数的修饰也是不行的,比如template<typename T> class<T>{...},至少你也得搞个const T之类的吧,呵呵。下面是我搞出来的几种特殊情况,它们都是正确的:

template<typename T1, typename T2>

class X {};

template<typename T>

class X<vector<T>, T&> {};

template<typename T>

class X<vector<T>, int&> {};

template<>

class X<vector<double>, int&> {};

template<typename T1, typename T2, typename T3>

class X<map<T1,T2>, T3&> {};

最后,还有一种超级牛X的,在tr1里面用以实现function的,以前我都没见过还可以这么玩的:

template<typename T>

class Y;//这是在声明一个类模板,既然声明了,以后就得按这个规矩来,在我们之前的编程经验里,可以重复声明一个东西没问题,但是为同一个东东重复声明出不同的东西就不可以了,因此你就不能再声明诸如template<typename T1, typename T2> class Y;这样的声明了;其实没有什么是不能声明的,既然我们可以声明变量,声明函数,声明类,那么当然我们也可以声明函数模板或者类模板的。

template<typename R, typename P1, typename P2>

class Y<R (P1, P2)> {...};//针对带两个参数,有返回值的函数类型特化,这里R (P1,P2)是定义了一种类型,该类型是一个隐式的函数指针,返回R,参数为P1P2,这种对函数指针的定义完全等同于R (*)(P1,P2),但是前一种定义很不常见,大家一般是不会注意到这个地方的。

最后:模板元:

主要转自:http://www.cnblogs.com/salomon/archive/2012/06/04/2534787.html

利用模板特化机制实现编译期条件选择结构,利用递归模板实现编译期循环结构,模板元程序则由编译器在编译期解释执行。

优劣及适用情况

通过将计算从运行期转移至编译期,在结果程序启动之前做尽可能多的工作,最终获得速度更快的程序。也就是说模板元编程的优势在于:

  1.以编译耗时为代价换来卓越的运行期性能(一般用于为性能要求严格的数值计算换取更高的性能)。通常来说,一个有意义的程序的运行次数(或服役时间)总是远远超过编译次数(或编译时间)。

  2.提供编译期类型计算,通常这才是模板元编程大放异彩的地方。

模板元编程技术并非都是优点:

  1.代码可读性差,以类模板的方式描述算法也许有点抽象。

  2.调试困难,元程序执行于编译期,没有用于单步跟踪元程序执行的调试器(用于设置断点、察看数据等)。程序员可做的只能是等待编译过程失败,然后人工破译编译器倾泻到屏幕上的错误信息。

  3.编译时间长,通常带有模板元程序的程序生成的代码尺寸要比普通程序的大,

  4.可移植性较差,对于模板元编程使用的高级模板特性,不同的编译器的支持度不同。

总结:

模板元编程技术不适用普通程序员的日常应用,它常常会做为类库开发的提供技术支持,为常规模板代码的内核的关键算法实现更好的性能或者编译期类型计算。模板元程序几乎总是应该与常规代码结合使用被封装在一个程序库的内部。对于库的用户来说,它应该是透明的。

技术细节

模板元编程使用静态C++语言成分,编程风格类似于函数式编程,在模板元编程中,主要操作整型(包括布尔类型、字符类型、整数类型)常量和类型,不可以使用变量、赋值语句和迭代结构等。被操纵的实体也称为元数据(Metadata),所有元数据均可作为模板参数。

由于在模板元编程中不可以使用变量,我们只能使用typedef名字和整型常量。它们分别采用一个类型和整数值进行初始化,之后不能再赋予新的类型或数值。如果需要新的类型或数值,必须引入新的typedef名字或常量。

其它范例

// 仅声明

struct Nil;

// 主模板

template <typename T>

struct IsPointer

{

    enum { Result = false };

    typedef Nil ValueType;

};

 

// 局部特化

template <typename T>

struct IsPointer<T*>

{

    enum { Result = true };

    typedef T ValueType;

};

 

// 示例

int main()

{

    cout << IsPointer<int*>::Result << endl;

    cout << IsPointer<int>::Result << endl;

    IsPointer<int*>::ValueType i = 1;

    //IsPointer<int>::ValueType j = 1; 

    // 错误:使用未定义的类型Nil

}

 

//主模板

template<bool>

struct StaticAssert;

 

// 完全特化

template<>

struct StaticAssert<true>

{};

 

// 辅助宏

#define STATIC_ASSERT(exp)\

{ StaticAssert<((exp) != 0)> StaticAssertFailed; }

 

int main()

{

    STATIC_ASSERT(0>1);

}

 

这个东西真是复杂,怪不得不招人待见。明天再总结函数模板。

努力不辍。

  评论这张
 
阅读(802)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017