Я укажу вам, в чем заключается критическая разница между Boost.Lambda и Boost.Phoenix:
Boost.Phoenix поддерживает (статически) полиморфные функторы, тогда как привязки Boost.Lambda всегда мономорфны.
(В то же время во многих аспектах две библиотеки могут быть объединены, поэтому они не являются исключительными вариантами выбора.)
Позвольте мне проиллюстрировать (Предупреждение: код не проверен.) :
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
может быть объединено в более сложное выражение без потери его полиморфного поведения.
Попытка лямбды
Что ближе всего мы можем получить к этому в Boost.Lambda ?, мы могли бы определить две перегрузки:
bool is_odd_overload(unsigned arg1){return arg1 % 2 == 1;}
bool is_odd_overload(long arg1){return arg1 % 2 == 1;}
но для создания лямбда-функции «ленивый» нам нужно будет выбрать один из двух:
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, но это другой вопрос.)
Подводя итог, можно сказать, что при заданной полиморфной функции / функторе лямбда не может связываться с полиморфной функцией (насколько я знаю), в то время как Феникс может. Это правда, что Phoenix опирается на «Result Of Protocol» http://www.boost.org/doc/libs/1_54_0/libs/utility/utility.htm#result_of, но 1) по крайней мере, это возможно, 2) Это меньше проблем в C ++ 11, где очень легко вывести типы возврата и это можно сделать автоматически.
На самом деле, в C ++ 11 лямбды Phoenix все еще более мощные, чем C ++ 11
встроенные лямбды. Даже в C ++ 14, где template общие лямбды
реализован, Феникс еще более общий, потому что он позволяет
определенный уровень самоанализа. (Для этого другое, Джоэл де
Гусман (разработчик Феникса) был и остается далеко впереди своего
время.)