Boost Phoenix 入门 (4)

Function

 

#include <boost/spirit/home/phoenix/function/function.hpp>

 

Phoenix 中的 function 可不是 boost 的泛型函数指针,它是用来帮助你实现 lazy function 的。把一个自己的函数实现成 lazy function 的主要好处就是,它可以和 Phoenix 的其它模块和谐共处。这个我们先按下不表,以后用到的时候,再详细解释。

 

Operator

 

#include <boost/spirit/home/phoenix/operator.hpp>

 

这个模块重载了几乎所有可以重载的 C++ 操作符,提供的当然是它们的 lazy 版本。事实上,正是由于有了这些 lazy operators,上一篇中这样的代码才成为可能:

std::generate(v.begin(), v.end(), ref(i)++)
std::for_each(v.begin(), v.end(), cout << arg1 << " ");  

其中的 ++, << 都被解析为重载后的 lazy 版本。 

 

Statement

 

#include <boost/spirit/home/phoenix/statement.hpp>

 

这个模块非常有趣,它提供了许多 C++ 语句,例如 if, else, while, switch, 甚至 try...catch 的 lazy 版本。可以说,它是在用 C++ 实现一个 lazy 版本的 C++!

这样说来比较抽象,我们看看一个例子:

#include <algorithm> #include <boost/spirit/home/phoenix/core.hpp> #include <boost/spirit/home/phoenix/operator.hpp> #include <boost/spirit/home/phoenix/bind.hpp> #include <boost/spirit/home/phoenix/statement.hpp> using namespace std; using namespace boost::phoenix; using namespace boost::phoenix::arg_names; struct Person { string name; uint age; Person() {} Person(string const& _name, uint _age) : name(_name) , age(_age) {} void greet() { cout << "Hello, " << name << endl; } void greet(string const& _s) { cout << _s << name << endl; } }; int main() { typedef vector<Person> PersonList; PersonList pl; pl.push_back(Person("Amy", 20)); pl.push_back(Person("Rose", 21)); pl.push_back(Person("Ralph", 30)); pl.push_back(Person("Zoe", 50)); std::for_each(pl.begin(), pl.end(), if_(bind(&Person::age, arg1) < 25) [ bind(&Person::greet, arg1, "Hi, young ") ]. else_ [ bind(&Person::greet, arg1) ] ); std::for_each(pl.begin(), pl.end(), switch_(bind(&Person::age, arg1)) [ case_<30>(cout << bind(&Person::name, arg1) << ", you stand by yourself." << endl), case_<50>(cout << bind(&Person::name, arg1) << ", you know your fate." << endl), default_(cout << bind(&Person::name, arg1) << ", enjoy your life!" << endl) ] ); return 0; }  

输出:

Hi, young Amy
Hi, young Rose
Hello, Ralph
Hello, Zoe
Amy, enjoy your life!
Rose, enjoy your life!
Ralph, you stand by yourself.
Zoe, you know your fate.

使用 if_, else_, switch_,case_,我们大大拓展了 for_each 的用途,实现了一些相当复杂的循环。我们可以想象,把这些 lazy statement 和其他的那么多 STL 算法结合起来,可以发挥多大的威力。

 

 

Object

 

#include <boost/spirit/home/phoenix/object.hpp>

 

Object 模块包括7个组件,分别对应 C++ 的构造函数,new, delete, const_cast, static_cast, dynamic_cast 和 reinterprete_cast 的 lazy 版本。

还是看个例子,如果我们想要用 vector 建立一个数字金字塔,如下面的样子,那该怎么写呢?

 


2 2 
3 3 3 
4 4 4 4 
5 5 5 5 5 
6 6 6 6 6 6 
7 7 7 7 7 7 7 
8 8 8 8 8 8 8 8 
9 9 9 9 9 9 9 9 9 
10 10 10 10 10 10 10 10 10 10 

当然,写一个双层循环没任何问题,这也是大家刚学编程的时候常见的练习题,不过用 Phoenix 的 lazy constructor 结合 STL,我们可以只用一句话就搞定:
#include <iostream> #include <vector> #include <algorithm> #include <boost/spirit/home/phoenix/core.hpp> #include <boost/spirit/home/phoenix/operator.hpp> #include <boost/spirit/home/phoenix/object.hpp> #include <boost/spirit/home/phoenix/statement.hpp> #include <boost/spirit/home/phoenix/container.hpp> using namespace std; using namespace boost::phoenix; using namespace boost::phoenix::arg_names; int main() { typedef vector<vector<int> > Matrix; Matrix m(10); int i = 1; generate(m.begin(), m.end(), construct<vector<int> >(ref(i)++, ref(i))); for_each(m.begin(), m.end(), ( for_(ref(i) = 0, ref(i) < size(arg1), ++ref(i)) [ cout << arg1[ref(i)] << " " ], cout << val("/n") ) ); return 0; }  

 

上面的代码里,用来把 Matrix m 初始化成一个金字塔的代码只有一句:

generate(m.begin(), m.end(), construct<vector<int> >(ref(i)++, ref(i)));

其中的魔法是这样的:

STL 的 generate 会在 m 的最外层循环,每一次都把 construct<vector<int> >(ref(i)++, ref(i))) 的结果赋予 m 的一个元素;
construct<vector<int> > 会在栈上构造一个 vector<int>,参数为后面两个:ref(i)++ 和 ref(i);
ref(i) 每次都返回一个自增的 i,第一个成为 vector<int> 的元素个数,第二个成为初始值。
于是,我们得到了这个数字金字塔,非常简洁。相反,我们的打印代码倒是挺长,而且利用了 lazy 的 for 语句。有没有什么简单一点的办法呢?有的,但是要等到我们讲完了 lazy container 和 lazy algorithm 再说。 

Bind

Phoenix 的 bind 和 boost.bind 差不多,但是更加健全些,我们在前面的 Statement 例子中已经用到过了。这里强调一下的是,它可以成功处理重载函数,在 Statement 例子里,bind 根据后面参数的个数,自动选择了正确的 greet 重载版本。

你可能感兴趣的:(Algorithm,function,String,each,Constructor,Matrix)