我会指出 Boost.Lambda 和 Boost.Phoenix 之间的关键区别是什么:
Boost.Phoenix 支持(静态)多态函子,而 Boost.Lambda 绑定总是单态的。
(同时,这两个库在很多方面是可以组合的,所以它们不是排他性的选择。)
让我说明一下(警告:代码未测试。):
凤凰
在 Phoenix 中,仿函数可以转换为 Phoenix“惰性函数”(来自http://www.boost.org/doc/libs/1_54_0/libs/phoenix/doc/html/phoenix/starter_kit/lazy_functions.html)
struct is_odd_impl{
typedef bool result_type; // less necessary in C++11
template <typename Arg>
bool operator()(Arg arg1) const{
return arg1 % 2 == 1;
}
};
boost::phoenix::function<is_odd_impl> is_odd;
is_odd
是真正的多态(作为函子is_odd_impl
)。那就是is_odd(_1)
可以作用于任何东西(这是有道理的)。例如在is_odd(_1)(2u)==true
和中is_odd(_1)(2l)==true
。is_odd
可以组合成更复杂的表达式,而不会失去其多态行为。
Lambda 尝试
在 Boost.Lambda 中我们最接近这个的是什么?我们可以定义两个重载:
bool is_odd_overload(unsigned arg1){return arg1 % 2 == 1;}
bool is_odd_overload(long arg1){return arg1 % 2 == 1;}
但是要创建一个 Lambda “惰性函数”,我们必须选择以下两者之一:
using boost::lambda::bind;
auto f0 = bind(&is_odd_overload, _1); // not ok, cannot resolve what of the two.
auto f1 = bind(static_cast<bool(*)(unsigned)>(&is_odd_overload), _1); //ok, but choice has been made
auto f2 = bind(static_cast<bool(*)(long)>(&is_odd_overload), _1); //ok, but choice has been made
即使我们定义了一个模板版本
template<class T>
bool is_odd_template(T arg1){return arg1 % 2 == 1;}
例如,我们必须绑定到模板函数的特定实例
auto f3 = bind(&is_odd_template<unsigned>, _1); // not tested
既不f1
是f2
也不f3
是真正的多态,因为在绑定时已经做出了选择。
(注 1:这可能不是最好的例子,因为从 unsigned 到 long 的隐式转换,事情似乎可以正常工作,但这是另一回事。)
总而言之,给定一个多态函数/仿函数 Lambda 不能绑定到多态函数(据我所知),而 Phoenix 可以。确实,Phoenix 依赖于“协议结果” http://www.boost.org/doc/libs/1_54_0/libs/utility/utility.htm#result_of但 1)至少有可能,2)这在 C++11 中问题不大,返回类型很容易推断并且可以自动完成。
事实上,在 C++11 中,Phoenix lambdas 仍然比 C++11 内置的 lambdas 更强大。即使在实现模板泛型 lambda 的 C++14 中,Phoenix 仍然更通用,因为它允许一定程度的自省。(为此,Joel de Guzman(Phoenix 的开发人员)曾经并且仍然远远领先于他的时代。)