C++ 模板元编程笔记
PREFACE
参考书籍 Reference Book:
- C++ Templates: The Complete Guide 2nd Edition
版权声明:本文受到 Creative Commons BY-NC-SA 协议的著作权保护,转载或改编时,请署名原作者。
Copyright: WRITTEN BY RYKER ZHU in Shanghai under CC BY-NC-SA
提示:您可以通过单击网页右侧的目录以快速导航至您需要查看的内容。
Tips: You can click on the table of contents on the right sidebar of the web page to navigate.
本笔记为中英双语,在没有合适的中文对应翻译时,会直接保留英文原名,不便之处敬请谅解。
除有特殊说明的外,所有以粗斜体标出的皆为概念、以粗体标出的为关键点或者小节标题。文中所有代码皆使用 Apache License 2.0 协议授权。
2023年 夏
于上海
祝禾 著
The Basics
Function Templates
编译模板需要经过两个阶段:
- 定义阶段 (Definition Time),在该阶段会在忽略掉模板参数的前提下检查错误,也就是和模板参数无关的错误;
- 实例化阶段 (Instantiation Time),在该阶段经过模板实例化之后,会进行全面错误检查。
Class Templates
Nontype Template Parameters
Variadic Templates
Tricky Basics
Move Semantics and
enable_if<>
C++11 起引入了移动语义 (Move Semantics) 这一特性,利用这个特性可以避免在调用拷贝构造函数时,其深度拷贝引发的时间和空间开销问题。
一类应用移动语义特性的典型如下:
1 |
|
在上述代码中 another
这个形参是右值引用
Object &&
的形式,“移动”
所做的就是将传入的右值的字段 data
移为己有;为了保证调用析构函数 ~Object()
时,data
指向的对象不会被析构两次(右值引用的值在表达式语句结束之后就会马上被析构),所以将数据偷过来之后还需要把原本右值的字段变成空指针,这样析构空指针就不会引发错误了。
简而言之,移动语义就只干了两件事:
- 将右值的字段移为己用;
- 置空右值字段。
由于本质上只是传递了指针,其时间和空间开销近乎可以忽略不计,相比深度拷贝来说,所需的代价小了不少。
Perfect Forwarding
完美转发 (Perfect Forwarding),一言以蔽之,就是确保参数在传递过程中,原有的属性限定符保持不变。
少说废话,直接上代码:
1 |
|
在上述代码中,定义了两个函数(只看函数名而不是函数签名的话)operation
以及
forward
,后者仅仅是将参数原封不动地传给前者。需要注意的是
forward
的第三个函数重载,这里用了 std::move
函数,作用是将左值转换成右值,因为虽然其看上去是右值引用
Type&&
,但实际上是 Type&
这个左值。
如果要用函数模板来实现的话虽然可以写成这个形式:
1 |
|
但是对于右值引用却没法很好地转发,因此 C++11 起可以写成以下形式以同时支持上述三种参数类型:
1 |
|
上面的 T&&
称为转发引用 (forwarding reference,
C++17 标准规定的术语) 或者是 万能引用
(universal reference),但是需要注意,这里的 T
是待推导的类型而不是具体的类型,比如 int&&
就不是转发引用。