Search code examples
c++boostboost-phoenix

Using Boost.Phoenix's operator ->*


I'm playing around with Phoenix v3 trying to figure out whether we should standardize on it instead of the current mix of Bind and Lambda. From the documentation I got the impression that it should be possible to simplify some expressions.

Currently I'm stuck on the usage of the ->* operator in combination with the STL algos. The following will compile (Visual Studio 2008 SP1) but not give the expected output:

#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;
}

Running this example will print out 'A' twice, both times for the bind-based loops. So here are my questions:

  • What should I change in order to have the operator-based loop actually call A::f?
  • How could I change the double-bind loop using operators?
  • Anyone know why VS2008 is always complaining when you don't specify mem_fn in these cases? I always get warning C4180 (qualifier applied to function type has no meaning; ignored).

Thanks in advance for any insights.


Solution

  • I am also not too good at phoenix but I think you cannot use the ->* operator the way you want it to use.
    If you change your example to

    ...
        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)());
    ...
    

    you will get two times A. In the examples I only found examples with pointers so I guess you can only use the phoenix ->* operator with pointers. Which should be ok as the operator ->* binds to pointers.
    From the Spec in 5.5:

    The binary operator ->* binds its second operand, which shall be of type “pointer to member of T” (where T is a completely-defined class type) to its first operand, which shall be of type “pointer to T” or “pointer to a class of which T is an unambiguous and accessible base class