#include <boost/spirit/home/phoenix/function/function.hpp>
Phoenix 中的 function 可不是 boost 的泛型函数指针,它是用来帮助你实现 lazy function 的。把一个自己的函数实现成 lazy function 的主要好处就是,它可以和 Phoenix 的其它模块和谐共处。这个我们先按下不表,以后用到的时候,再详细解释。
#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 版本。
#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 算法结合起来,可以发挥多大的威力。
#include <boost/spirit/home/phoenix/object.hpp>
Object 模块包括7个组件,分别对应 C++ 的构造函数,new, delete, const_cast, static_cast, dynamic_cast 和 reinterprete_cast 的 lazy 版本。
还是看个例子,如果我们想要用 vector 建立一个数字金字塔,如下面的样子,那该怎么写呢?
1
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
上面的代码里,用来把 Matrix m 初始化成一个金字塔的代码只有一句:
generate(m.begin(), m.end(), construct<vector<int> >(ref(i)++, ref(i)));
其中的魔法是这样的:
Phoenix 的 bind 和 boost.bind 差不多,但是更加健全些,我们在前面的 Statement 例子中已经用到过了。这里强调一下的是,它可以成功处理重载函数,在 Statement 例子里,bind 根据后面参数的个数,自动选择了正确的 greet 重载版本。