posts - 200, comments - 8, trackbacks - 0, articles - 0

C++模板元编程 入门简介 (转)

Posted on 2012-12-01 20:01 鑫龙 阅读(302) 评论(0)  编辑 收藏 引用 所属分类: c++

最近一直在看STL和Boost,源码里边好多涉及到模板元编程技术,简单了解一下,备忘(Boost Python中的涉及模板元的部分重点关注一下)。

范例引入

// 主模板
template<int N>
struct Fib
{
    
enum { Result = Fib<N-1>::Result + Fib<N-2>::Result };
};

// 完全特化版
template <>
struct Fib<1>
{
    
enum { Result = 1 };
};


// 完全特化版
template <>
struct Fib<0>
{
    
enum { Result = 0 };
};

int main()
{
    
int i = Fib<10>::Result;
    
// std::cout << i << std::endl;
}

主要思想

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

优劣及适用情况

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

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

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

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

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

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

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

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

总结:

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

工程应用实例

1. Blitz++:由于模板元编程最先是因为数值计算而被发现的,因此早期的研究工作主要集中于数值计算方面,Blitz++库利用模板将运行期计算转移至编译期的库,主要提供了对向量、矩阵等进行处理的线性代数计算。

2.Loki:将模板元编程在类型计算方面的威力应用于设计模式领域,利用元编程(以及其他一些重要的设计技术)实现了一些常见的设计模式之泛型版本。Loki库中的Abstract Factory泛型模式即借助于这种机制实现在不损失类型安全性的前提下降低对类型的静态依赖性。

3.Boost:元编程库目前主要包含MPL、Type Traits和Static Assert等库。 Static Assert和Type Traits用作MPL的基础。Boost Type Traits库包含一系列traits类,用于萃取C++类型特征。另外还包含了一些转换traits(例如移除一个类型的const修饰符等)。Boost Static Assert库用于编译期断言,如果评估的表达式编译时计算结果为true,则代码可以通过编译,否则编译报错。

技术细节

模板元编程使用静态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);
}
 

 

References:

http://club.topsage.com/thread-421469-1-1.html

http://wenku.baidu.com/view/c769720df78a6529647d539d.html

Blitz++: http://www.oonumerics.org/blitz .
Loki :http://sourceforge.net/projects/loki-lib

Boost:http://www.boost.org/


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理