第1章模板元编程Ⅰ.docx
《第1章模板元编程Ⅰ.docx》由会员分享,可在线阅读,更多相关《第1章模板元编程Ⅰ.docx(14页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、模板元编程(I)C+是一种功能强大到几乎可称为“万能”的语言,支持许多种不同的编程范式,而由 泛型编程衍生出的模板元编程(template meta-programing,简称元编程)则无疑是其中 最复杂、最强大和最具威力的一种,可算得上是C+的“终极”技巧(传说中的“大杀器”,笑)。所谓“元程序”metaprogram,意思就是a program about a program”,它有着完全不同于普通程序的许多特点,是一种全新的编程体验。作为本书的第一章,首先 来讨论模板元编程的一些基本概念,它们是许多Boost程序库组件的基础,了解模板元编程 有助于我们对Boost的进一步学习。1.1 模
2、板元编程概述元编程也可译为“超程序”、“超编程”或“产生式编程”,这个译法一定程度上反映了 其本质一一它是一种位于普通程序之上、超越普通程序的程序,是一种可以操纵、产生程序 的程序。C+ +中的模板元编程是无意中被“发现”而不是“发明”出来的,是一种对“类型”计 算的程序,关于它的诞生有许多有趣的传奇和故事。模板元编程本质上是泛型编程的一个子 集,从广义上来说,所有使用template的泛型代码都可以称作是元程序,因为泛型代码不 是真正可编译执行的代码,它们只是定义了代码的产生规则,是用来生成代码的“模板”。然而模板元编程又不完全等同于泛型编程,它是一种“函数式编程”,并且已经被证明 是图灵完
3、备的,也就是说它具有足够的“计算”能力,可以“计算”任何东西。模板元编程 的执行是在编译期,它把编译器变成了元程序的解释器,可以把C+的类型体系像面团一样 is_class is_enum is_union is_complex is_pointer:检查T是否是一个class或者struct;:检查T是否是一个枚举类型;:检查T是否是一个联合类型;:检查T是否是一个标准库的复数类型(std: : complex );:检查T是否是一个指针或函数指针类型,但不是成 员指针; is_lvalue_reference :检查T是否是一个左值引用类型; is_rvalue_reference :检查
4、T是否是一个右值引用类型; is_reference:检查T是否是一个引用类型(左引用或右引用); is_function:检查T是否是一个函数类型,但不是函数指针或引用。下面的代码示范了其中部分元函数的用法:assert(mp_eval(is_array);assert(mp_eval(is_array);/一维数组类型/多维数组类型assert(mp_eval(is_class);assert(mp_eval(is_classstd:vector );/一个空类标准容器类assert (mp_eval (is_comp 1 exstd: : complex );/复数assert (mp_
5、eval (is_pointer);assert(mp_eval(is_pointer);整型指针函数指针assert(mp_eval(is_reference) ) ;/弓I用assert (mp_eval (is_referencestd: :deque const&); 容器常弓I用assert(mp_eval(is_function);函数类型检查成员指针类型最后是两个专门用于识别类成员指针类型的元函数:is_union的功能实现需要编译器的支持,有的编译器会把union识别为class/structotype_traits库原木只有is_reference,Boost 1.45版后增
6、加了对左弓I用(T&)和右弓I用(T&)的区分,但因为右引用语法是2+11里的新特性,故无法在C+98标准中进行测试,请读者见谅。 is_member_object_pointer :检查T是否是指向成员变量的指针; is_member_function_pointer :检查T是否是一个成员函数指针。示范这两个元函数用法的代码如下:struct dummy(int x;double y;void func()/一个简单的类/int成员变量 /double成员变量成员函数assert(mp_eval(is_member_object_pointer);assert(mp_eval(is_mem
7、ber_object_pointer);assert(mp_eval(is_member_function_pointer);1.2.3 元数据类别(II )在16个基本元函数之上,type_traits库又提供了六个检查复合类别(composite traits)的元函数,它们相当于多不基本类别的组合,使用:valu返回bool类型的检 查结果,列举如下: is_arithmetic:检查T是否是算术类型,相当于is_integralT | | is_float; is_fundamental:检查T是否是基本类型,相当于is_arithmetic1 I is_void; is_compou
8、nd:检查T是否是复合类型,即非基本类型,相当于! is_ fundamental; is_member_pointer :检查T是否是成员指针,包括指向数据成员和函数成 is_object员的指针,相当于 is_member_object_pointer | is_member_function_pointer;:检查T是否是实体对象类型,即引用、void和函数之 外的所有类型,相当于! is_reference & ! is_ void & !is function; is scalar:检查T是否是标量类型,即算术类型、枚举、指针和成员指针,相当于 is_arithmeticT | |
9、is_enum | | is_pointer | | is_member_pointero示范这些检查复合类别元函数的代码如下:/char是算术类型/float是算术类型/void不是算术类型/void是基本类型assert(mp_eval(is_arithmetic);assert(mp_eval(is_arithmetic);assert(!mp_eval(is_arithmetic);assert (mp_eval (is_fundamentaKvoid const);assert (mp_eval (is_member_pointer);戊员指专I,标准字符串是复合类型标准字符串也是对
10、象类型int是标量类型标准容器不是标量类型assert(mp_eval(i s_compound); assert(mp_eval(is_object);assert(mp_eval(is_scalar);assert(!mp_eval(is_scalarstd:vector );1.2.4 元数据属性除了检查类别,type_traits库里还有更多的元函数用于获取元数据更细致的属性。 这些元函数都是值元函数,以is_和has_开头的元函数使用:value返回bool类型的检 查结果,其他元函数使用:valu返回整数。检查数组的属性 rank :如果T是数组,那么返回数组的维数,否则返回0;
11、extent:如果T是数组,那么返回数组第N个维度(从0计数)的值,否则 返回0。检查基本的修饰词 is_const :检查T是否被const修饰; is_volatile:检查 T 是否被 volatile 修饰; is signed :检查T是否是有符号整数; is_unsigned:检查T是否是无符号整数。检查class的属性 is_pod is_empty is_abstract:检查T是否是一个POD类型;:检查T是否是一个空类(可参见小节);:检查T是否是一个抽象类(有纯虚函数); is_polymorphic :检查T是否是一个多态类(有虚函数)。检查class的四大成员函数(构
12、造、析构、拷贝构造和赋值) has_nothrow_constructor :检查T是否有不抛出异常的构造函数; has_nothrow_default_constructor:检查T是否有不抛出异常的缺省构造函数; has_trivial_constructor :检查T是否有“平凡”的构造函数; has_trivial_default_constructor:检查 T 是否有“平凡”的缺省构造函数; has_trivial_destructor :检查T是否有“平凡”的析构函数; has_virtual_destructor :检查T是否有虚析构函数; has_nothrow_copy:检
13、查T是否有不抛出异常的拷贝构造函数; has_nothrow_copy_constructor: 同 has_nothrow_copy; has_trivial_copy:检查T是否有“平凡”的拷贝构造函数; has_trivial_copy_constructor:同 has_trivial_copy; has_nothrow_assign:检查T是否有不抛出异常的赋值函数;POD是术语Plain Old Data的缩写,但没有明确的定义。通常来说基本类型(is_fundamental: value = true)都是POD,而复合类型的POD则没有构造函数、析构函数、废函数,内存布局是连
14、续的,与C语言定义的类型等价。trivial”这个术语在C+中是指“平凡”、“非特殊”的含义,“平凡”的构造、析构函数没有任何 操作,“平凡”的拷贝构造函数、赋值函数类似于memcpy操作,因而可以被编译器优化。 has_trivial_assign:检查T是否有“平凡”的赋值函数。其他属性 has_new_operator :检查 T 是否重载了 operator new; is_stateless :检查T是否是一个无状态类,即一个“平凡”的空类; alignment_of :T在内存中字节对齐的倍数。以上一共列举了 25个属性检查元函数,下面的代码简要示范了其中部分元函数的用法:获得数组
15、inti 2 3的维数assert(mp_eval(rank) = 2);因extent。有多个元参数,失效,只能使用原始形式获取第二个维度标准字符串不是POD类型函数对象是空类标准流是多态的assert(extent:value = 3);assert(!mp_eval(is_pod);assert(mp_eval(is_emptystd:plus );assert (mp_eval (is_jpolymorphic);标准字符串的构造函数和拷贝构造函数可能会抛出异常assert(!mp_eval(has_nothrow_constructor);assert(!mp_eval(has_no
16、throw_copy);/验证各个类型的字节对齐assert(mp_eval(alignment_of) = 1);assert(mp_eval(alignment_of) = 4);assert(mp_eval(alignment_ofstd:vector ) = 4);1.2.5 元数据之间的关系type_traits库提供四个元函数计算元数据之间的关系,它们都是两参值元函数,使 用::value返回bool类型的检查结果:捏来捏去,肆意打碎再任意组合起来,拥有近乎不可思议的“魔力”。虽然模板元编程使用的是标准的C+语言,遵循同样的语法规则,但它在编程思想、编 程范式等很多方面都与普通的运
17、行时C+程序有很大的不同。模板元编程产生的元程序是在 编译期执行的程序,操作的对象也不是普通的变量,因此不能使用运行时的C+ +关键字(如 if、else, for),可用的语法元素相当有限,最常用的是: enum. static,用来定义编译期的整数常量; typedef,最重要的元编程关键字,用于定义元数据; template,模板元编程的“起点”,主要用于定义元函数; “:”,域运算符,用于解析类型作用域获取计算结果(元数据)。下面简单介绍模板元编程领域中的三个最基本的概念,熟悉它们才能够理解模板元编程 和元程序。当然元编程中远不止这些,还有lambda表达式、容潜、迭代潜、算法、视图等
18、 更高级的概念,它们将在本书的第11章叙述。1.1.1 元数据元编程可操作的数据就称为“元数据(metadata),也就是C+编译器在编译期可操 作的数据,它是元编程的基础。元数据都是不可变的,不能够就地修改,最常见的元数据是整数和C+的类型(type)。对于整数大家都很熟悉,普通程序在运行时也可以很容易地处理,但在模板元编程中的 元数据更多的是以类型(type)的面目出现。这些元数据不是普通的运行时变量,而是如 int. double, class (非模板类)这样的抽象数据类型一一这是模板元编程与普通运行时 编程的一个最根本的不同点,也是元编程的威力所在(类型的计算)和令初学者感到最困惑
19、的地方。如果对元数据再进行细分归类,则元数据又可以分成整数元数据、值型元数据(int、 double等POD值类型)、函数元数据(函数类型)、类元数据(class、struct等用户自 定义类型)等等。为了更明确地表述元数据的概念,本书后面的“元数据” 一词特指非整数 的类型元数据。使用typedef关键字可以任意定义(声明)元数据,很像运行时的变量定义语句, 例如:元数据meta datal,值为inttypedef int meta_datal;元数据 meta_data2,值为 vectortypedef std:vector meta_data2;1.1.2 元函数元函数(meta f
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 模板 编程
限制150内