关于 C++ 模板编程的惯用法,note-to-self + keynote + idiom case + cross-reference 式笔记
模板语法^
称谓:函数模板 (function template) vs. 模板函数 (template function),或 类模板 (class template) vs. 模板类 (template class),见 [CPP TEMP] 7.1
两阶段编译 (two-phase lookup)、第一实例化点 (first point of instantiation),见 [CPP LANG] 13.2.5 [CPP TEMP] 2.1.2
实例化 (instantiation) 和特化(又译专门化)(specialization)、生成的特化 (generated specialization) vs. 显式的特化 (explicit specialization),见 [CPP LANG] 13.2.2, C.13.7 [CPP TEMP] 7.2
不完全实例化 (incomplete instantiation),见 [CPP LANG] 13.2.2 [MODERN CPP] 1.8
完全特化 (complete specialization)、部分特化(又译偏特化)(partial specialization),见 [CPP LANG] 13.5 [CPP TEMP] 3.3, 3.4
特化顺序:更特化 (more specialized)、更泛化 (more general)、原始模板 (primary template),见 [CPP LANG] 13.5.1 [CPP TEMP] 7.2
非类型模板参数,见 [CPP LANG] 13.2.3 [CPP TEMP] 4
函数模板和普通函数间的重载,见 [CPP LANG] 13.3.2 [CPP TEMP] 2.4
函数模板的参数推导 (argument deduction),见 [CPP LANG] 13.3.1, C.13.4 [CPP TEMP] 2.2, 11
默认模板参数,见 [CPP LANG] 13.4.1 [CPP TEMP] 3.5
成员模板 (member template),见 [CPP LANG] 13.6.2 [CPP TEMP] 5.3
模板作为模板参数 (template template parameter),见 [CPP LANG] C.13.3 [CPP TEMP] 5.4
typename 限定词 (typename qualifier),见 [CPP LANG] C.13.5 [CPP TEMP] 5.1 [EFFECT CPP] Item 42
template 限定词 (template qualifier),见 [CPP LANG] C.13.6 [CPP TEMP] 5.1
模板代码组织:包含模型 (inclusion model) vs. 分离模型 (separation model) 又称分别编译 (separate compile),见 [CPP LANG] 13.7 [CPP TEMP] 6.1, 6.3
显式实例化 (explicit instantiation),见 [CPP LANG] C.13.10 [CPP TEMP] 6.2
设计思维:运行时多态 (run-time polymorphism) vs. 编译时多态 (compile-time polymorphism) 又称参数化多态 (parametric polymorphism),见 [CPP LANG] 13.6.1 [EFFECT CPP] Item 41 [CPP TEMP] 14
模板惯用法示例^
堆栈上分配^
on-stack allocation 的 std 案例:tr1::array 模板
使用模板方法的不足之处是使用编译时确定的 buffer size,为了能在运行时动态调整 stack 内存分配数量,可借助 VC CRT 的 _alloca, _malloca 函数
示例:一个 printf 式的生成 std::string 的函数
- template <size_t BufSize, class CharT>
- inline
- std::basic_string<CharT> make_string(const CharT* format, ...)
- {
- CharT buf[BufSize];
- va_list args;
- va_start(args, format);
- // vsprintf 是函数模板, 其针对 char 特化调用 vsprintf_s, 针对 wchar_t 特化调用 vswprintf_s
- vsprintf(buf, BufSize, format, args);
- va_end(args);
- // 注意: 返回时构造可让 VC 编译优化为只有一次 string ctor 调用, 没有额外 copy
- return std::basic_string<CharT>(buf);
- }
编译优化的开关^
bool 模板参数,或整数模板参数 + 阈值,避免重复代码时借助编译优化
示例:一个支持透明色的 32bit blit 函数
- template <bool UseMask>
- void blit(int* dst, const int* src, int mask, size_t size)
- {
- for (size_t i = 0; i < size; i++, dst++, src++) {
- if (!UseMask || *src != mask)
- *dst = *src;
- }
- }
推导数组元素个数^
可由参数推导求出数组的元素个数,要求必须是数组名,而非指向数组的指针或 new[] 数组
示例:VC CRT 的 _countof 计算数组的元素个数
- // 以 C++ 方式编译时, _countof 的定义如下
- template <typename _CountofType, size_t _SizeOfArray>
- char (*__countof_helper(UNALIGNED _CountofType (&_Array)[_SizeOfArray]))[_SizeOfArray];
- #define _countof(_Array) (sizeof(*__countof_helper(_Array)) + 0)
示例:多数 VC CRT buffer 操作函数都有 Secure Template Overloads 版本
- template <size_t size>
- errno_t strcpy_s(char (&strDestination)[size], const char *strSource);
推导常数^
示例:掩码常数 Mask<N>::Value
- #define _MASK_VAL(x) (1 << x)
- // 用于代替上面的宏