17

Boost.Phoenix を使用することの本当の利点を理解できません。

Boost.Spirit 文法で使用すると、非常に便利です。

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

ラムダ関数に使用すると、便利でエレガントです。

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

しかし、このライブラリの他のすべての利点は何ですか? ドキュメントには、「ファンクターはどこにでもある」と書かれています。よく分からんけど何がいいの?

4

5 に答える 5

13

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)==trueis_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 の開発者) は当時も今も時代を先取りしています。)

于 2011-02-17T05:48:21.523 に答える
5

まあ、それは非常に強力なラムダ言語です。

これを使用して、数学のような 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

于 2011-02-16T07:30:42.983 に答える
4

フェニックス使ったことないけど…

Phoenix Library docsから:

Phoenix ライブラリは、高階関数、ラムダ (名前のない関数)、カリー化 (部分関数適用)、および C++ での遅延評価などの FP 手法を可能にします。

関数型プログラミングに関するウィキペディアの記事から:

... 関数型プログラミングは、計算を数学関数の評価として扱い、状態と変更可能なデータを回避するプログラミング パラダイムです。状態の変化を強調する命令型プログラミング スタイルとは対照的に、関数の適用を強調します。

したがって、Phoenix は C++ で関数型プログラミングを有効にするためのライブラリです。

最近の関数型プログラミングへの主な関心は、副作用を制限または排除することにより、正確性とパフォーマンスにおいて認識された利点に由来しているようです。

正しさは、副作用がなければ、表示されるコードがシステム内で行われているすべてであるためです。他のコードは、あなたの下の状態を変更しません。この種の環境では、バグのないコードをはるかに簡単に記述できます。

副作用がないため、作成したコードはリソース管理プリミティブやアトミック アクセス トリックなしで安全に並列実行できるため、パフォーマンスが向上します。マルチスレッドは非常に簡単に、さらには自動的に有効にすることができ、非常に効率的に動作します。

于 2011-02-16T07:21:53.103 に答える
3

Boost.Phoenix2 を見ないでください。

ブーストでのラムダ式の進化は次のようになります。

Bind -> Lambda, Phoenix2 (Spirit partとして) -> Phoenix3 (別ライブラリとして、開発中)。

結果は、ポリモーフィック ファンクターをサポートする単一のラムダ ライブラリです (他のファンクターは非推奨になる予定です)。

于 2011-02-28T17:28:30.390 に答える
1

C++での関数型プログラミング。以前にSMLなどの関数型プログラミングを適切にサポートする言語を使用したことがない限り、説明するのは困難です。私はPhoenixを使おうとしましたが、それは素晴らしいと思いましたが、コンパイル時間が大幅に長くなり、何か間違ったことをするとエラーメッセージがひどくなるため、実際のプロジェクトでは非常に実用的ではありません。フェニックスで遊んだときに、GCCから数メガバイトのエラーが発生したことを覚えています。また、深くネストされたテンプレートのインスタンス化のデバッグはPITAです。(実際、これらはブーストのほとんどを使用することに反対するすべての議論でもあります。)

于 2011-02-16T07:13:55.927 に答える