Я укажу вам, в чем критическая разница между 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
можно объединить в более сложное выражение без потери полиморфного поведения.
Лямбда-попытка
Что ближе всего к этому можно получить в 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 по-прежнему более эффективны, чем встроенные лямбда-выражения C++11. Даже в C++14, где реализованы универсальные лямбда-выражения template, Phoenix по-прежнему более универсален, поскольку допускает определенный уровень самоанализа. (В этом и в остальном Джоэл де Гусман (разработчик Phoenix) был и остается далеко впереди своего времени.)
person
alfC
schedule
17.02.2011