Boost.Lambda と Boost.Phoenix の決定的な違いは何かを指摘します。
Boost.Phoenix は (静的に) ポリモーフィック ファンクターをサポートしますが、Boost.Lambda バインドは常にモノモーフィックです。
(同時に、多くの面で 2 つのライブラリを組み合わせることができるため、排他的な選択肢ではありません。)
説明しましょう(警告: コードはテストされていません。) :
フェニックス
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
は真に多態的です ( functor としてis_odd_impl
)。つまりis_odd(_1)
、何でも実行できます (これは理にかなっています)。たとえば、is_odd(_1)(2u)==true
とis_odd(_1)(2l)==true
. is_odd
ポリモーフィックな動作を失うことなく、より複雑な式に組み合わせることができます。
ラムダ試行
Boost.Lambda でこれに最も近いものは何でしょうか? 2 つのオーバーロードを定義できます。
bool is_odd_overload(unsigned arg1){return arg1 % 2 == 1;}
bool is_odd_overload(long arg1){return arg1 % 2 == 1;}
ただし、Lambda の「遅延関数」を作成するには、次の 2 つのいずれかを選択する必要があります。
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 が「Result Of プロトコル」 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 でも、Phoenix はより一般的です。(これはまた別の話ですが、Joel de Guzman (Phoenix の開発者) は当時も今も時代を先取りしています。)