Note
1 MP
(1) 思想
`模板 用于 [1] 编译时计算 [2] 生成代码 (类和函数)`
1) 两级编程
2) 模板元编程 TMP
MP = "元数据" + 程序设计: 使用 他人 元程序/元编程结果, 不是 元编程
(2) 目的
[1] `类型安全` 提高
可 `计算` 数据结构或算法 所需 `确切类型` -> `消除` 很多 `显式类型转换`
[2] `运行时性能` 提高
1] `编译期计算` 并 `选择 运行时要调用的函数`
-> 将 `多态行为` 解析为 `直接 函数调用`
2] 用 `紧凑内存布局` 的 data structure
(3) vs GP
1) 区分的意义: 聚焦问题重点
—————————————————————————————————————————————————————————————————————————
| 关注的焦点 | 本质: 是一种 | 目的
—————————————————————————————————————————————————————————————————————————
[1] GP | 接口说明 | 设计 哲学 | 通用 类型 或 算法
—————————————————————————————————————————————————————————————————————————
[2] MP | 计算 | 编程/实现 技术 | 类型安全 + 运行时性能 高
—————————————————————————————————————————————————————————————————————————
2)
[1] GP 可划归为 MP 第1级: `无计算`
[2] 可支持 GP
对象分配构想 // 28.1 节
On_heap 和 Scoped 用于 Obj_holder
|_ _ _ _ _| |
| |
|/ |/
GP TMP
(4) 4 个等级
—————————————————————————————————————————————
[1] 无计算
仅 传递 `类型 和 值 实参`
—————————————————————————————————————————————
[2] `简单计算`: 类型 或 值 上
单位(Unit)相加 // 28.5 节
值上简单计算
———————————————————————————————————————————————————————————————
[3] `编译时检测` 的 计算
编译时选择器 std::conditional
———————————————————————————————————————————————————————————————
[4] `编译时迭代` 的 计算
阶乘 的 3种版本( 编译时计算, 版本2 还可以 运行时计算 )
———————————————————————————————————————————————————————————————
(5) 2 种实现
1] constexpr 函数 -> `只接受值, 且 只生成值` -> 优选 constexpr 函数, 而不是 TMP
2] 模板 -> TMP
(6) 过度使用
MP + 宏
|
|
|/
隐藏 `实现细节 + 糟糕的命名`
|
| 解决: 系统化的技术
|/
(类型)别名 + 特例化
2 编译时计算
(1) 优选 constexpr 函数, 而非 `模板`
(2) 尽可能 `隐藏` constexpr 函数中 `TMP 实现细节`
template<typename T>
constexpr bool Is_pod()
{
return std::is_pod<T>::value;
} |
|/
TMP
3 模板
(1) 目标
[1] 通用性
[2] 生成最优代码
(2) vs FP ( 函数式编程 )
模板 构成了完整的 `编译时 FP`
28.1 类型函数: 接受 (多个)类型参数 / 生成 (多个)类型结果
(1) 接受 `类型参数` -> 返回 `类型实参` 的 `关联成员 值/类型 ::value/::type`
(2) 广义形式: 模板类( 如 iterator_traits ) -> 关联(成员)类型 (别名)
1 类型 别名: 提取 类型 typename ::type
模板别名
[1] `更像 类型`
[2] 隐藏 ::type 实现细节
// 条件 true, 选则 T, else F
template<bool C, typename T, typename F>
using Conditional = typename std::conditional<C, T, F>::type;
2 类型 谓词: 提取 值 ::value
谓词: 返回 bool 值 的 (类) 函数
std::is_pod<T>::value 是 `POD 类型` 吗 ?
std::is_polymorphic<T>::value 是 `多态类型` 吗 ?
封装: `模板函数 + constexpr`
[1] 统一表示 Is_pod<T>()
[2] 隐藏实现细节
template<typename T>
constexpr bool Is_pod()
{
return std::is_pod<T>::value;
}
综合 Conditional & Is_pod<T>()
Conditional<Is_pod<T>(), On_heap<T>, Scoped<T> > x;
3 选择 函数(对象): 编译时选择 -> {} 构造 函数对象 -> () 调用 operator()
Conditional<(sizeof(int) > 4), X, Y>{}(3);
using Type = Conditional<(sizeof(int) > 4), X, Y>;
Type t;
t(3);
struct X
{
void operator()(int x) { /**/ }
};
// Y 类似
4 萃取 traits: 提取类型 的 associated type
萃取 及其 等价特性 ( auto / decltype() ):
(1) 目的: 将 1个 类型(属性: value_type) 与 another 类型(迭代器: T*) 关联起来
(2) 应用: 非侵入式 添加类型: not change 目的类型/Iterator
template<typename Iterator>
struct iterator_traits
{
using value_type = typename Iterator::value_type;
};
template<typename T>
using Value_type = typename std::iterator_traits<T>::value_type;
// ... Difference_type
template<typename Iter>
Iter search(Iter p, Iter q, Value_type<Iter> val)
{
Difference_type<Iter> m = q - p;
// ...
}
|
| auto / decltype()
|/
template<typename Iter, typename Val>
Iter search(Iter p, Iter q, Val val)
{
auto m = q - p; // 若 不需要 命名 q - p 的 类型
using difference_type = decltype(q - p); // 若 需要 命名 q - p 的 类型
// ...
}
28.2 控制结构
1 选择
(1) 运行时选择: 普通 if 对 类型选择 无效, 因 if 语句分支 不能 是 声明 作 唯一语句
if(My_cond<T>() )
using type = Square; // error
else
using type = Cube;
type x; // error
(2) 编译时选择器
Conditional<My_cond<T>(), Square, Cube>{}(99); // Ctor + operator()
My_cond<T>() ? Square{}(99) : Cube{}(99);
// error
( My_cond<T>() ? Square : Cube ){}(99); // ?: 后 2各操作数 不是表达式 -> 语法错
|
( My_cond<T>() ? Square{} : Cube{} )(99); // ?: 后 2各操作数 类型不相容 -> 语法错
2 迭代 和 递归: 编译时迭代 用 递归 实现
阶乘3版本
version1: TMP + constexpr 函数(模板)
version2: MP: constexpr 函数 - 条件运算符 ? ::
version3: 类(struct)模板
比较
version1/3 只支持 `编译时求值`, version2 还支持 `运行时求值`
version1/2 性能一样 -> version2 更清晰
// === version1
template<int N>
constexpr int fac()
{
return N*fac<N-1>();
}
template<>
constexpr int fac<1>()
{
return 1;
}
constexpr int x1 = fac<5>();
// === version2
constexpr int fac(int i)
{
return (i<2) ? 1: fac(i - 1);
}
constexpr int x2 = fac(5);
// === version3
template<int N>
struct Fac
{
static const int value = N*Fac<N-1>::value;
};
template<>
struct Fac<1>
{
static const int value = 1;
};
constexpr int x3 = Fac<5>::value;
28.3 编译时 列表: Tuple/元组
1 简单输出函数
2 元素访问
3 make_tuple
28.4 可变参数模板
1 类型安全的 printf()
2 机制
2种 参数包
模板参数包 typename... Args
函数参数包 ... args
... 0或多个
(1) use 第1个 elem
(2) (函数)参数包展开: args... -> 递归调用
[1] 剥离 headElem
[2] left 实参 捆包到 (函数)参数包 ...args
28.5 国际标准单位 例子
1 Unit
类型函数: 对象分配构想.png
image.png
28.5 - 1 Tuple 1.jpg
28.5 - 1 Tuple 2.jpg
28.5 - 1 Tuple3.jpg
28.5 - 2 Tuple 元素访问 1.jpg
28.5 - 2 Tuple 元素访问 2.jpg
28.5 - 3 make_tuple.jpg
28.6 可变参数模板: 引入.jpg
可变实参 的 4 种实现.jpg
28.6 - 1 类型安全的 printf().jpg
28.6 - 1 类型安全的 printf().jpg
28.6 -2 技术细节.jpg
28.6 - 3 转发.jpg
28.6 - 4 标准库 tuple.jpg
28.7 国际标准: 用 constexpr 和 模板, 几乎可以在 `编译时计算` 任何东西.jpg
Unit 加法.jpg
建议.jpg












网友评论