版权所有 © 2018 T. Zachary Laine
根据 Boost 软件许可证版本 1.0 发布。(参见随附文件 LICENSE_1_0.txt 或在 https://boost.ac.cn/LICENSE_1_0.txt 复制)
目录
“我喜欢用引言来开始文档。一条好而精辟的引言。”
— Eric Niebler (转述)
表达式模板很棒。它们被用于许多库中;这里仅列出三个最令人印象深刻的
然而,这可能会付出高昂的代价。表达式模板的实现和维护成本很高。 Eigen 和 Boost.Ublas 中的每一个都包含大量复杂的表达式模板代码,这些代码无法在其他地方重用。
借助 C++14 和 C++17 标准提供的语言功能,现在可以轻松编写和使用表达式模板库,并且编译时间非常合理。
举个快速的例子,假设我们正在进行一些矩阵运算,并编写了如下语句
D = A * B + C;
其中所有变量都是矩阵。事实证明,为 A * B 创建一个临时变量,然后再为结果的乘积加上 C 创建另一个临时变量是非常低效的。大多数矩阵数学库将提供一个函数,该函数一次性完成所有操作
mul_add_assign(D, A, B, C);
如果您使用的矩阵库同时提供这两种语法,您必须注意到何时应将某个使用运算符的代码替换为更高效的函数;这既繁琐又容易出错。如果库根本不提供运算符语法,只提供更高效的函数调用,则使用该库的代码的可写性和可读性会大大降低。
使用 Boost.YAP,您可以编写一些库代码,使诸如 D = A * B + C 这样的表达式自动转换为类似 mul_add_assign(D, A, B, C) 这样的表达式。
再考虑另一个例子。我们中的许多人都使用过 Unix 命令行工具来删除文件中的重复行
sort file_with_duplicates | uniq > file_without_duplicates
当然,我们可以使用标准算法做一些非常类似的事情
std::vector<int> v1 = {0, 2, 2, 7, 1, 3, 8}; std::sort(v1.begin(), v1.end()); auto it = std::unique(v1.begin(), v1.end()); std::vector<int> const v2(v1.begin(), it); assert(v2 == std::vector<int>({0, 1, 2, 3, 7, 8}));
然而,如果我们的代码能做到这一点,但使用更简洁的语法会更好
std::vector<int> v1 = {0, 2, 2, 7, 1, 3, 8}; std::vector<int> const v2 = sort(v1) | unique; assert(v2 == std::vector<int>({0, 1, 2, 3, 7, 8}));
这看起来与上面的 Unix 命令行非常相似。(让我们假设 Range-v3 还不具备几乎完全相同的 Yet。)
Boost.YAP 可以用于实现这两个目标,而且代码量相当少。事实上,如果您想看看第二个如何实现,可以直接跳转到 可管道化的算法 示例。
evaluate(transform(expr)) 成语预计将是使用 Yap 操作和求值表达式的最常见方式之一。