MPL11 技术文档
1. 安装指南
MPL11 是一个头文件库。要在您的项目中使用它,只需将 include
目录添加到编译器的头文件搜索路径中即可。
该库没有依赖项,甚至不依赖标准库。但是,它需要一个支持 C++14 的编译器。测试套件在以下编译器中通过:
- clang 版本 3.4
- clang 版本 3.5.0
- GCC 4.9.0 20140302 (实验性)
- Apple LLVM 版本 5.1 (clang-503.0.38)
要编译单元测试,您还需要安装 [CMake]。安装完成后,您可以进入项目根目录并执行以下命令:
$ mkdir build
$ cd build
$ cmake ..
$ make tests # 编译单元测试。
精简版本
MPL11 也提供了一个精简版本。要使用它,只需包含 boost/mpl11.min.hpp
头文件,其中包含整个库。请注意,精简头文件不得与其他库头文件一起使用。
2. 项目使用说明
MPL11 是一个基于 C++11 的库,提供用于解决复杂模板元编程问题的可组合、高级基元。该库围绕几个核心概念构建;本教程的目的是介绍这些概念,而库提供的工具则留给了 参考文档。
本教程假设您对模板元编程和基本函数编程概念有很好的理解。此外,了解 Boost.MPL 库也将有所帮助。但是,MPL11 在很多方面都与 Boost.MPL 有所不同,因此在将知识从一个库转移到另一个库时,需要检查文档。
3. 项目 API 使用文档
以下是 MPL11 库的一些关键概念和使用的简要说明。
Metafunctions
非正式地,元函数是一个模板,表示一个编译时函数,它接受类型作为参数并返回一个类型作为结果。来自 MPL 的读者应该注意,这里的正式定义与 MPL 的定义不同。
正式地,设 f
为一个具有任意数量类型模板参数的 C++ 模板,且仅具有类型模板参数。如果存在类型 x1, ..., xn
使得 f<x1, ..., xn>::type
是一个有效的类型名,则 f
是一个 元函数。在这种情况下:
x1, ..., xn
是f
的 参数。- 形成特化
f<x1, ..., xn>
被称为 暂停f
与x1, ..., xn
。 - 特化
f<x1, ..., xn>
被称为 thunk 或 suspension。 - Thunk 的嵌套
::type
被称为 thunk 的 结果。如果 thunk 的形式为f<x1, ..., xn>
,我们也可以说它是f
与x1, ..., xn
的结果。 - 获取 thunk 的结果称为 评估 thunk。如果 thunk 的形式为
f<x1, ..., xn>
,我们也可以说 调用f
与x1, ..., xn
或 应用f
到x1, ..., xn
。 - 元函数的 arity 是它可以被调用的参数数量。具有 n 个参数的元函数被称为 n-ary 元函数。
- 一个可以接受任意数量参数的元函数被称为 可变参数。根据定义,可变参数元函数对于任何非负整数 n 都是 n-ary。
重要的是要注意这个定义与 Boost.MPL 给出的定义之间的区别。根据这个定义,元函数永远不能是普通的 C++ 类型;它必须始终是模板。因此,Boost.MPL 实现为非模板类的零元元函数不被视为元函数。
以下是一些示例:
// 一个一元元函数。
template <typename x>
struct unary { struct type; };
// 一个二元元函数。
template <typename x, typename y>
struct binary { struct type; };
// 一个可变参数元函数。
template <typename ...>
struct variadic { struct type; };
// 一个零元元函数。它只能被调用 0 个参数,因此它是 0-ary(零元)。
template <typename ...> struct nullary;
template <> struct nullary<> { struct type; };
// 不是 MPL11 的元函数;它不是模板!
struct MPL_nullary { struct type; };
// 不是元函数;它从不具有结果(一个嵌套的 ::type)!
template <typename ...>
struct no_result { };
Boxed Types
非正式地,boxed 类型是一个尚未被评估的类型。因此,在知道boxed类型的实际“值”之前,必须评估它,这个过程称为解包。
正式地,对于任意的 C++ 类型 T
,一个 boxed T
是一个任意的 C++ 类型 B
,使得 B::type
是 T
。在这种情况下,B
被称为 box(of T
)和解包 T
的过程称为 unboxing T
。
struct T;
struct B { using type = T; }; // 一个boxed T(等价于T的box)
B::type; // 解包T
相反,将任意类型 T
包裹在类型 B
中,使得 B::type
是 T
被称为 boxing T
(到 B
或用 B
)。重要的是要注意 B
可能依赖于 T
,没有这一点,boxed 将失去其意义。
struct T;
template <typename t>
struct B { using type = t; };
B<T>; // 将T boxing到B
请注意,类型可以被boxed任意次。这可能不是很有用,但定义足够通用以允许它。
B<B<T>>; // 这是一个“B<T>的box”,即“T的box的box”
存在一个特殊的boxed类型名为 undefined
(有时称为_bottom_),其特点是当它被解包时,即使在 SFINAE-able 上下文中也会导致编译时错误。undefined
可以被视为无效值或失败的计算结果。
以下是一些示例来说明前面的定义:
// 这个模板接受一个任意类型T并boxed它。
template <typename T>
struct box {
using type = T;
};
// 这些不是boxed。
class x;
struct y { char foo; };
char;
box<char>::type;
// 这些是boxed类型。
box<char>; // 一个boxed `char`
box<box<char>>; // 一个boxed `box<char>`
box<box<char>>::type; // 一个boxed `char`
struct x { using type = char; }; // 一个boxed `char`
struct y { struct type; }; // 一个boxed `y::type`
struct z { using type = z; }; // 自引用?为什么不!
重要的是要注意,boxed T
有很多不同的表示。这使得boxed类型之间的等价关系变得有点复杂。考虑以下内容:
struct T;
struct B1 { using type = T; }; // 一个boxed T
struct B2 { using type = T; }; // 另一个boxed T
当然,B1
和 B2
在他们boxed的类型上是等价的,因为他们都boxed了同一个类型 T
。但是,B1
和 B2
在 C++ 类型系统上是不等价的,因为他们是不同的类型。现在,这很重要,因为它告诉我们不能使用模式匹配来定义一个接受boxed类型作为参数的元函数。确实,由于boxed类型的表示不是唯一的,我们无法预知我们的参数将具有什么形式,因此无法进行模式匹配。考虑以下内容:
// B 应该是一个boxed类型。
template <typename B>
struct f;
// 这应该处理boxed chars,但我们不知道boxed char可能看起来像什么!
template <>
struct f<????> {
// ...
};
现在,我们可能会尝试这样做:
// box 是我们之前定义的模板。它接受一个任意类型并boxed它。
template <>
struct f<box<char>> {
// ...
};
但是后来...
template <typename T>
struct bad {
using type = T;
};
// 如预期那样工作
f<box<char>>::type;
// 即使 bad<char> 显然是一个boxed char,也不工作
f<bad<char>>::type;
相反,我们可能需要进行更复杂的操作,如:
template <typename T>
struct f_impl;
template <>
struct f_impl<char> {
using type = ...;
};
template <typename B>
struct f
: f_impl<typename B::type>
{ };
f<box<char>>::type; // 工作
f<bad<char>>::type; // 也工作
有趣的是,boxed 类型和 thunks 之间有很多相似之处。实际上,thunk不过是通过 suspending 一个元函数形成的boxed类型。因此,每当boxed类型被期望时,都可以使用 thunk 代替。
- mybatis-plusmybatis 增强工具包,简化 CRUD 操作。 文档 http://baomidou.com 低代码组件库 http://aizuda.comJava00
- open-eBackupopen-eBackup是一款开源备份软件,采用集群高扩展架构,通过应用备份通用框架、并行备份等技术,为主流数据库、虚拟化、文件系统、大数据等应用提供E2E的数据备份、恢复等能力,帮助用户实现关键数据高效保护。HTML055
- 每日精选项目🔥🔥 12.27日推荐:解锁高效测试的新工具-Shortest🔥🔥 每日推荐行业内最新、增长最快的项目,快速了解行业最新热门项目动态~~018
- Cangjie-Examples本仓将收集和展示高质量的仓颉示例代码,欢迎大家投稿,让全世界看到您的妙趣设计,也让更多人通过您的编码理解和喜爱仓颉语言。Cangjie042
- 毕方Talon工具本工具是一个端到端的工具,用于项目的生成IR并自动进行缺陷检测。Python039
- PDFMathTranslatePDF scientific paper translation with preserved formats - 基于 AI 完整保留排版的 PDF 文档全文双语翻译,支持 Google/DeepL/Ollama/OpenAI 等服务,提供 CLI/GUI/DockerPython03
- advanced-javaAdvanced-Java是一个Java进阶教程,适合用于学习Java高级特性和编程技巧。特点:内容深入、实例丰富、适合进阶学习。JavaScript0103
- taro开放式跨端跨框架解决方案,支持使用 React/Vue/Nerv 等框架来开发微信/京东/百度/支付宝/字节跳动/ QQ 小程序/H5/React Native 等应用。 https://taro.zone/TypeScript09
- Yi-CoderYi Coder 编程模型,小而强大的编程助手HTML012
- excelizehttps://github.com/xuri/excelize Excelize 是 Go 语言编写的一个用来操作 Office Excel 文档类库,基于 ECMA-376 OOXML 技术标准。可以使用它来读取、写入 XLSX 文件,相比较其他的开源类库,Excelize 支持操作带有数据透视表、切片器、图表与图片的 Excel 并支持向 Excel 中插入图片与创建简单图表,目前是 Go 开源项目中唯一支持复杂样式 XLSX 文件的类库,可应用于各类报表平台、云计算和边缘计算系统。Go02