首先,对于不熟悉 Phoenix 的读者,先介绍一下 Phoenix 是什么。Phoenix 的作者,Joel de Guzman,也就是 Boost.Spirit 的作者,在看到许多往 C++ 中引入 Functional Programming 的努力以后,决定把 Spirit 优雅的设计思想用于建立一个 C++ 的 Functional Programming 库,这就是 Phoenix 了。Joel 自己是这样说的:

Phoenix is a blend of FC++ and BLL using the implementation techniques used in the Spirit inline parser. Phoenix version 2, this version, will probably be the last release of the library. Phoenix v2 will be the basis of the Phoenix and BLL merger.

如雷贯耳吧,Spirit,FC++ 和 BLL (Boost Lambda Library) 的结合会是什么样子?Phoenix 2 就是一份答卷。

先来个初步印象,用 Phoenix 2 ,我们可以办到 BLL 能办到的事情:

#include <vector>
#include <iostream>
#include <boost/spirit/phoenix/core.hpp>
#include <boost/spirit/phoenix/operator.hpp>

using namespace boost::phoenix;

int main()
{
std::vector<int> vec(10);
std::partial_sum(vec.begin(), vec.end(), vec.begin(), _2 = _1 + 1);

std::for_each(vec.begin(), vec.end(), std::cout << _1 << " " );
}

输出:

0 1 2 3 4 5 6 7 8 9

没错,这些在我以前介绍 Boost.Lamda 的时候都用过,程序可以原封不动的搬过来使用 Phoenix 2 。

Phoenix 2 几乎采用了 Boost.Lamda 的所用东西,对某些作了语法上的改动,使之更加一致和清晰。例如我们想要输出上面 vec 当中所有大于5的元素,便可以用到 Phoenix 2 中的 statement :

#include <iostream>
#include <algorithm>
#include <numeric>
#include <vector>
#include <boost/spirit/phoenix/core.hpp>
#include <boost/spirit/phoenix/operator.hpp>
#include <boost/spirit/phoenix/statement.hpp>

using namespace boost::phoenix;

int main()
{
std::vector<int> vec(10);
std::partial_sum(vec.begin(), vec.end(), vec.begin(), _2 = _1 + 1);

std::for_each(vec.begin(), vec.end(),
if_ ( _1 > 5 )
[
std::cout << _1 << ", "
]
);
}

输出:

6, 7, 8, 9,

这是什么东西?注意,我们没有真的把 if 放到 for_each 里面,我们放进去的是 if_ ,这是一个 Phoenix 定义的 statement,它的作用和 C++ "原生"的 if 是一样的。可能你还会注意到 if_ 后面是 [ ] 而不是我们熟悉的 { },这是 Phoenix 2 对 Boost.Lambda 的改进(在 Lambda 里面,我们有的时候用 ( ),有的时候用 [ ] ,缺乏一致性)。“真无聊“,我听到有人在说,“我自己写个循环不是一样么”。当然,如果是这样,我们甚至可以不用 for_each,for 循环是万能的;我们还可以不用 vector,数组也完全可以办到这些……这些 statement 存在的意义,在于我们可以 "inline" 的编写相当复杂的 lambda 表达式,例如我如果不希望输出最后一个逗号,可以把输出的语句换成这样:

std::cout << _1 << if_else(_1 < 9, ", ", "")

这里的 if_else 是专门用来替代 C++ 的 : , 操作符的,我们知道 C++ 不允许重载这个操作符,所以 Phoenix 2 采用了这个办法,不过依我看来,它反而比 : , 更加清晰。

当然,if_ 是可以接 else_ 的,看看下面,注意语法:

std::for_each(vec.begin(), vec.end(),
if_ ( _1 > 5 )
[
std::cout << _1 << if_else(_1 < 9, ", ", "")
]
.else_
[
std::cout << _1 << "<=5, "
]
);

输出:

0<=5, 1<=5, 2<=5, 3<=5, 4<=5, 5<=5, 6, 7, 8, 9

注意 else_ 前面有一个 . 这有这样,它们才能被编译器看作同一个表达式而接受。

#include <iostream>
#include <algorithm>
#include <numeric>
#include <vector>
#include <boost/spirit/phoenix/core.hpp>
#include <boost/spirit/phoenix/operator.hpp>
#include <boost/spirit/phoenix/statement.hpp>

using namespace boost::phoenix;

int main()
{
std::vector<int> vec(10);
std::partial_sum(vec.begin(), vec.end(), vec.begin(), _2 = _1 + 1);

std::for_each(vec.begin(), vec.end(),
(
while_ ( --_1 >= 0 )
[
std::cout << _1 << if_else(_1 > 0, ", ", "")
],
std::cout << val('\n')
)
);
}

输出:

0
1, 0
2, 1, 0
3, 2, 1, 0
4, 3, 2, 1, 0
5, 4, 3, 2, 1, 0
6, 5, 4, 3, 2, 1, 0
7, 6, 5, 4, 3, 2, 1, 0
8, 7, 6, 5, 4, 3, 2, 1, 0

在这个程序中,我们除了看到 while_ ,还看到如何把几个语句并列起来:放在括号里,用逗号隔开,当然这是 C++ 的常识了,只不过在这种场合显得特别有用。这个语句有一个副作用:由于参数是 by ref 传递的,所以在执行过程中,vec 中的元素的值已经被更改了,如果你在语句之后输出 vec 所有的元素,你会得到:

-1 -1 -1 -1 -1 -1 -1 -1 -1 -1

我们甚至可以在 for_each 中使用 for 循环,这就要用到 Phoenix 2 的 for_ statement:

#include <iostream>
#include <algorithm>
#include <numeric>
#include <vector>
#include <boost/spirit/phoenix/core.hpp>
#include <boost/spirit/phoenix/operator.hpp>
#include <boost/spirit/phoenix/statement.hpp>

using namespace boost::phoenix;

int main()
{
std::vector<int> vec(10);
std::partial_sum(vec.begin(), vec.end(), vec.begin(), _2 = _1 + 1);

int i;
std::for_each(vec.begin(), vec.end(),
(
for_ ( var(i) = _1, var(i) >= 0, --var(i) )
[
std::cout << var(i) << if_else(var(i) > 0, ", ", "")
],
std::cout << val('\n')
)
);

std::cout << '\n';
for_each(vec.begin(), vec.end(), std::cout << _1 << " ");
}

输出:

0
1, 0
2, 1, 0
3, 2, 1, 0
4, 3, 2, 1, 0
5, 4, 3, 2, 1, 0
6, 5, 4, 3, 2, 1, 0
7, 6, 5, 4, 3, 2, 1, 0
8, 7, 6, 5, 4, 3, 2, 1, 0
9, 8, 7, 6, 5, 4, 3, 2, 1, 0

0 1 2 3 4 5 6 7 8 9

注意,for_ 的3个部分不是用分号,而是用逗号分隔的。为什么我们要用 var(i) 而不直接用 i ?这是为了使用 lazy evaluation ,如果直接用 i ,那么 i 会在语句执行之前被求值,而不是在语句执行的过程中被求值。Lazy evaluation 在 Functional Programming 中的地位至关重要。

在上面的例子中,我们必须在外面定义一个变量 i ,然后用 var 把它变成 Phoenix 2 能接受的表达式,难道我们必须这样?非也,Phoenix 2 甚至提供了方法来定义局部变量:

#include <iostream>
#include <algorithm>
#include <numeric>
#include <vector>
#include <boost/spirit/phoenix/core.hpp>
#include <boost/spirit/phoenix/operator.hpp>
#include <boost/spirit/phoenix/statement.hpp>
#include <boost/spirit/phoenix/scope.hpp>

using namespace boost::phoenix;
using namespace boost::phoenix::local_names;

int main()
{
std::vector<int> vec(10);
std::partial_sum(vec.begin(), vec.end(), vec.begin(), _2 = _1 + 1);

std::for_each(vec.begin(), vec.end(),
let ( _a = 0 )
[
for_ ( _a = _1, _a >= 0, --_a )
[
std::cout << _a << if_else(_a > 0, ", ", "")
],
std::cout << val('\n')
]
);

std::cout << '\n';
for_each(vec.begin(), vec.end(), std::cout << _1 << " ");
}

输出和前面的程序一样:

0
1, 0
2, 1, 0
3, 2, 1, 0
4, 3, 2, 1, 0
5, 4, 3, 2, 1, 0
6, 5, 4, 3, 2, 1, 0
7, 6, 5, 4, 3, 2, 1, 0
8, 7, 6, 5, 4, 3, 2, 1, 0
9, 8, 7, 6, 5, 4, 3, 2, 1, 0

0 1 2 3 4 5 6 7 8 9

其中 let 就是在 Phoenix 2 中使用局部变量的方法,Phoenix 2 预定义了26个局部变量 _a ~ _z,它们放在 boost::phoenix::local_names 命名空间内。

凤凰涅磐 --- Phoenix 2 发布预览相关推荐

  1. Flutter「发布预览版 2」让 iOS 应用至臻完美

    Flutter 是 Google 面向移动端应用推出的一套跨平台开发工具,助力开发者在 iOS 和 Android 两个平台上开发高质量的原生应用界面.为期两日的中国 2018 Google开发者大会 ...

  2. iOS【Flutter「发布预览版 2」让 iOS 应用至臻完美】

    Flutter 是 Google 面向移动端应用推出的一套跨平台开发工具,助力开发者在 iOS 和 Android 两个平台上开发高质量的原生应用界面.为期两日的中国 2018 Google开发者大会 ...

  3. 微软发布预览版SQL Server跨平台开发工具

    微软发布了预览版跨平台数据库开发工具SQL Operations Studio(SqlOps). \\ 该工具是Visual Studio Code的一个分支,可以运行在Windows.MacOS和L ...

  4. fancybox ajax post,发布预览-使用AJAX和Fancybox传递数据

    小编典典 正如我在评论中提到的那样,您的预览按钮应通过ajax提交表单以获取POST预览值(我们将使用ajax代替iframe),因此: Preview 然后,您需要将预览按钮绑定到手动on(&quo ...

  5. 仿APP“美篇”发布预览界面

    文章编辑页面

  6. Windows 11 首个预览版发布,最低配置要求或降低!

    整理 | 郑丽媛 出品 | CSDN(ID:CSDNnews) 自上周五 Windows 11 官宣,就有不少人在期待着年底正式版的到来.而在今天,有一部分人就可以提前体验 Windows 11 了: ...

  7. Pico VR 实时预览工具 Preview Tool,终于发布

    Pico 官方在 2022 年 4 月 2 号发布 XR 实时预览工具:Preview Tool v1.0 更新内容: 发布预览工具.具体介绍如下: 通过 Pico Unity/Unreal XR P ...

  8. 微软发布IE11预览版 主打速度比IE10快9%

    [CSDN.NET 报道]日前,微软对外发布了IE11预览版(下载),新版本主打速度(微软宣称在Win7下运行速度能比其他浏览器快30%),并实现了对WebGL等技术标准的支持. 更快的Web体验 在 ...

  9. SharePoint Framework 1.15 预览版更新 – 新功能发布

    微软近日宣布了 SharePoint Framework (SPFx) 1.15 预览版更新的消息,这次更新包括了 Viva Connections.Microsoft Teams和SharePoin ...

最新文章

  1. Linux命令之more
  2. 解决Ubuntu中无法连接wifi的方法
  3. 虚函数与纯虚函数的区别
  4. Eclipse配置CAS client
  5. celery java_Celery(分布式任务队列) 的使用方法总结
  6. Java 7:最新特性更新、代码示例及性能测试
  7. Nginx中修改php.ini的上传设置upload_max_filesize的值
  8. 图解数字签名-数字证书-公钥加密-私钥签名原理
  9. edge使用html2协议,微软推出Microsoft Edge WebView2控件 帮助开发者更好的加载网页
  10. 4000块一晚,住进地下88米深坑,这是全国首家AI超五星酒店
  11. PHPword 表格内换行处理
  12. vue upload上传图片
  13. 2020年小红书直播报告
  14. 51Nod-1299-监狱逃离
  15. 基于Python+Django+Vue+MYSQL的社团管理系统
  16. 中国电信移动物联网发展成果与创新实践 ,干货满满
  17. Linux上安装pstree命令(-bash: pstree: command not found)
  18. Apriori concept (antecedent and a consequence module)
  19. springboot 整合mysql clickhouse 多数据源
  20. oracle ogg端口,OGG报错 OGG-01223

热门文章

  1. 51单片机入门 - 基础知识汇总
  2. js如何实现扫描身份证识别_百度AI身份证识别demo,使用js提交图片数据
  3. 数学建模国赛2017年C题优秀论文(Word)(颜色与物质浓度辨识)
  4. Redis中的slots
  5. 代码随想录算法训练营第二十五天|216.组合总和III 17.电话号码的字母组合
  6. 18、包含网关(Inclusive Gateway)
  7. 第四范式正式成为OpenI 启智社区成员
  8. Jenkins 一直处于等待界面
  9. PCM以及G711编码
  10. 一文掌握GSEA通路富集分析,超详细教程!