首页
/ MPL11 技术文档

MPL11 技术文档

2024-12-28 09:28:01作者:农烁颖Land

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, ..., xnf参数
  • 形成特化 f<x1, ..., xn> 被称为 暂停 fx1, ..., xn
  • 特化 f<x1, ..., xn> 被称为 thunksuspension
  • Thunk 的嵌套 ::type 被称为 thunk 的 结果。如果 thunk 的形式为 f<x1, ..., xn>,我们也可以说它是 fx1, ..., xn 的结果。
  • 获取 thunk 的结果称为 评估 thunk。如果 thunk 的形式为 f<x1, ..., xn>,我们也可以说 调用 fx1, ..., xn应用 fx1, ..., 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::typeT。在这种情况下,B 被称为 box(of T)和解包 T 的过程称为 unboxing T

struct T;
struct B { using type = T; }; // 一个boxed T(等价于T的box)

B::type; // 解包T

相反,将任意类型 T 包裹在类型 B 中,使得 B::typeT 被称为 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

当然,B1B2 在他们boxed的类型上是等价的,因为他们都boxed了同一个类型 T。但是,B1B2 在 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 代替。

热门项目推荐
相关项目推荐

项目优选

收起
open-eBackupopen-eBackup
open-eBackup是一款开源备份软件,采用集群高扩展架构,通过应用备份通用框架、并行备份等技术,为主流数据库、虚拟化、文件系统、大数据等应用提供E2E的数据备份、恢复等能力,帮助用户实现关键数据高效保护。
HTML
74
55
openHiTLSopenHiTLS
旨在打造算法先进、性能卓越、高效敏捷、安全可靠的密码套件,通过轻量级、可剪裁的软件技术架构满足各行业不同场景的多样化要求,让密码技术应用更简单,同时探索后量子等先进算法创新实践,构建密码前沿技术底座!
C
51
39
HarmonyOS-ExamplesHarmonyOS-Examples
本仓将收集和展示仓颉鸿蒙应用示例代码,欢迎大家投稿,在仓颉鸿蒙社区展现你的妙趣设计!
Cangjie
258
66
mybatis-plusmybatis-plus
mybatis 增强工具包,简化 CRUD 操作。 文档 http://baomidou.com 低代码组件库 http://aizuda.com
Java
22
0
Cangjie-ExamplesCangjie-Examples
本仓将收集和展示高质量的仓颉示例代码,欢迎大家投稿,让全世界看到您的妙趣设计,也让更多人通过您的编码理解和喜爱仓颉语言。
Cangjie
177
42
advanced-javaadvanced-java
Advanced-Java是一个Java进阶教程,适合用于学习Java高级特性和编程技巧。特点:内容深入、实例丰富、适合进阶学习。
JavaScript
400
103
RuoYi-VueRuoYi-Vue
🎉 基于SpringBoot,Spring Security,JWT,Vue & Element 的前后端分离权限管理系统,同时提供了 Vue3 的版本
Java
168
37
RuoYi-Cloud-Vue3RuoYi-Cloud-Vue3
🎉 基于Spring Boot、Spring Cloud & Alibaba、Vue3 & Vite、Element Plus的分布式前后端分离微服务架构权限管理系统
Vue
27
18
hyperionhyperion
仓颉语言实现的TCP通信框架,支持添加自定义编解码器,积木式添加IoFilter处理入栈出栈消息。仓颉redis-sdk和activemq4cj项目使用了该框架。
Cangjie
113
16
CangjieCommunityCangjieCommunity
为仓颉编程语言开发者打造活跃、开放、高质量的社区环境
Markdown
892
0