使用Boost.Phoenix有什么好处?

时间:2011-02-16 07:07:00

标签: c++ boost boost-phoenix

我无法理解使用Boost.Phoenix的真正好处。

当我将它与Boost.Spirit语法一起使用时,它非常有用:

double_[ boost::phoenix::push_back( boost::phoenix::ref( v ), _1 ) ]

当我将它用于lambda函数时,它也是有用和优雅的:

boost::range::for_each( my_string, if_ ( '\\' == arg1 ) [ arg1 = '/' ] );

但是这个库中其他一切的好处是什么?文档说:“各地的Functors”。我不明白它的好处是什么?

5 个答案:

答案 0 :(得分:12)

我会指出Boost.Lambda和Boost.Phoenix之间的关键区别是什么:

Boost.Phoenix支持(静态)多态仿函数,而Boost.Lambda绑定总是单态的。

(与此同时,在许多方面,这两个图书馆可以合并,因此它们不是唯一的选择。)

让我说明(警告:未经过测试的代码。)

菲尼克斯

在凤凰城,一个仿函数可以转换成凤凰“懒惰函数”(来自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)==trueis_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

f1f2f3都不是真正的多态,因为在绑定时已做出选择。

(注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。即使在C ++ 14中, template 泛型lambda也是如此  实施后,凤凰城还是比较一般,因为它允许了  一定程度的内省。 (对于其他事情,乔尔德  Guzman(凤凰城的开发者)过去和现在都领先于他  时间。)

答案 1 :(得分:5)

嗯,这是一种非常强大的lambda语言。

我用它来创建类似数学的DSL的原型:

http://code.google.com/p/asadchev/source/browse/trunk/work/cxx/interval.hpp

以及许多其他事情:

http://code.google.com/p/asadchev/source/browse/#svn%2Ftrunk%2Fprojects%2Fboost%2Fphoenix

答案 2 :(得分:4)

我从未使用凤凰城,但......

来自the Phoenix Library docs

  

Phoenix库支持FP技术,如高阶函数,lambda(未命名函数),currying(部分函数应用程序)和C ++中的惰性求值

来自the Wikipedia article on Functional programming

  

...函数式编程是一种编程范式,它将计算视为数学函数的评估,并避免状态和可变数据。它强调功能的应用,与命令式编程风格形成对比,强调状态的变化

因此,Phoenix是一个用C ++实现函数式编程的库。

目前,功能编程的主要兴趣似乎来自于由于限制或消除副作用而在正确性和性能方面的优势。

正确性,因为没有副作用,您看到的代码就是系统中发生的一切。其他一些代码不会改变你下面的状态。在这种环境中,您可以更轻松地编写无错误的代码。

性能,因为没有副作用,您编写的代码可以安全地并行运行,无需任何资源管理原语或原子访问技巧。多线程可以非常容易地,甚至自动地启用,并且可以非常有效地运行。

答案 3 :(得分:3)

不要看Boost.Phoenix2。

boost中lambda表达式的演变如下:

绑定 - &gt; Lambda,Phoenix2(作为精神部分) - &gt; Phoenix3(作为独立的库,正在开发中)。

结果是具有多态仿函数支持的单个lambda库(其他的将被弃用)。

答案 4 :(得分:1)

C ++中的函数式编程。除非您以前使用过适当支持函数编程的语言,例如SML,否则很难解释。我尝试使用Phoenix并发现它很好,但在实际项目中非常不切实际,因为它大大增加了编译时间,并且当你做错了什么时错误消息很糟糕。当我和菲尼克斯一起玩时,我记得从GCC那里得到几兆的错误。此外,调试深层嵌套的模板实例化是PITA。 (实际上,这些也是反对使用大部分提升的所有论据。)