2

私はPhoenixv3で遊んでいて、現在のBindとLambdaの組み合わせではなく、標準化する必要があるかどうかを判断しようとしています。ドキュメントから、いくつかの表現を単純化することが可能であるはずだという印象を受けました。

現在、STLアルゴと組み合わせた->*演算子の使用に固執しています。以下はコンパイルされますが(Visual Studio 2008 SP1)、期待される出力は得られません。

#include <algorithm>
#include <iostream>
#include <vector>
#include <boost/mem_fn.hpp>
#include <boost/phoenix.hpp>
using namespace std;
using namespace boost;
using namespace boost::phoenix;
using namespace boost::phoenix::arg_names;

struct A
{
  void f() const { cout << "A"; };
};
struct B
{
  A a() { return A(); };
};

int main()
{
  vector<A> va(1);
  for_each(va.begin(), va.end(), bind(mem_fn(&A::f), arg1));
  for_each(va.begin(), va.end(), arg1->*&A::f);

  vector<B> vb(1);
  for_each(vb.begin(), vb.end(), bind(mem_fn(&A::f), bind(mem_fn(&B::a), arg1)));
  return 0;
}

この例を実行すると、バインドベースのループの場合は両方とも「A」が2回出力されます。だからここに私の質問があります:

  • オペレーターベースのループで実際にA::fを呼び出すには、何を変更する必要がありますか?
  • 演算子を使用してダブルバインドループを変更するにはどうすればよいですか?
  • このような場合にmem_fnを指定しないと、VS2008が常に文句を言う理由を知っている人はいますか?私は常に警告C4180を受け取ります(関数型に適用された修飾子は意味がありません;無視されます)。

洞察を事前に感謝します。

4

2 に答える 2

4

与えられた:

#include <algorithm>
#include <vector>
#include <iostream>
#include <boost/phoenix.hpp>

struct A
{
    void f() const { std::cout << "A\n"; };
};

struct B
{
    A a() const { return A(); };
};

最初のものは簡単な修正です:

int main()
{
    using boost::phoenix::arg_names::arg1;

    std::vector<A> va(1);
    std::for_each(va.begin(), va.end(), (&arg1->*&A::f)());
}

に関してoperator->*、Phoenixのドキュメントは明確に述べています:

メンバーポインタ演算子の左側は、ポインタ型を返すアクターである必要があります。

したがって、オブジェクト(この場合は)が与えられた場合、-A&を使用するには、そのオブジェクトのアドレスを取得する必要があります。(また、フェニックスのアクターは怠惰であるため、怠惰なファンクターではなく熱心なファンクターを取得するには、追加の括弧のセットを使用する必要があります。)operator->*&arg1


2つ目は、演算子だけを使用できないため、それほど簡単ではありません。使用するにはポインタを表すアクターoperator->*が必要なため、の結果のアドレスを取得する必要がありますが、B::aの結果B::aは右辺値です。そして、任意の右辺値のアドレスを取ることは違法です。2つのオプションがあります。

  1. の結果をB::a変数に格納し、それを左辺値にして、その結果、のアドレスを取得することを合法にします。これは、以下を使用して実行できますphoenix::let

    int main()
    {
        using boost::phoenix::let;
        using boost::phoenix::arg_names::arg1;
        using boost::phoenix::local_names::_a;
    
        std::vector<B> vb(1);
        std::for_each(
            vb.begin(),
            vb.end(),
            (let(_a = (&arg1->*&B::a)())[(&_a->*&A::f)()])
        );
    }
    

    明らかに、これはかなり醜いです。

  2. phoenix::bindの代わりに使用します。これはoperator->*、参照とポインターで同等に機能するため、B::a次の結果のアドレスを取得する必要がありません。

    int main()
    {
        using boost::phoenix::bind;
        using boost::phoenix::arg_names::arg1;
    
        std::vector<B> vb(1);
        std::for_each(vb.begin(), vb.end(), bind(&A::f, (&arg1->*&B::a)()));
    }
    
于 2011-07-21T18:43:21.783 に答える
1

私もフェニックスが苦手ですが、 ->* 演算子を思い通りに使えないと思います。
例を次のように変更すると

...
    vector<A*> va;
    va.push_back(new A);
    for_each(va.begin(), va.end(), bind(mem_fn(&A::f), arg1));
    for_each(va.begin(), va.end(), (arg1->*&A::f)());
...

A が 2 回得られます。例では、ポインターを使用した例しか見つけられなかったので、phoenix ->* 演算子のみをポインターで使用できると思います。演算子 ->* がポインターにバインドされるため、これは問題ありません。
5.5 の仕様から:

二項演算子 ->* は、「T のメンバーへのポインター」型 (T は完全に定義されたクラス型) である 2 番目のオペランドを、「T へのポインター」型である最初のオペランドにバインドします。 「T が明確でアクセス可能な基本クラスであるクラスへのポインタ

于 2011-07-21T11:35:35.053 に答える