1

I am trying to learn boost::phoenix and trying to use it in std::transform like below.

class myClass
{
   int i;

public:
   getNumber(); 
   setNumber(int j); 
};

int main()
{
   std::vector<myClass*> vect
   std::vector<int> numVect

   numVect.resize(vect.size());
   using boost::phoenix::arg_names::arg1;
   std::transform (vect.begin(), vect.end(), numVect.begin(), arg1->getNumber());
}

But, I am getting an error error: base operand of '->' has non-pointer type 'const boost::phoenix::actor<boost::phoenix::argument<0> >'

I am not really sure what does it mean. Any help would be great. Thanks

polapts
  • 5,493
  • 10
  • 37
  • 49
  • I suggest you give up. Don't take this the wrong way--I just think Phoenix is too complicated to use for real, and you've found a great example of why--most C++ users will never be able to help you fix this, much less figure out how to modify it later on. Just use a normal for loop or something. – John Zwinck Jul 04 '13 at 11:19
  • I appreciate your opinion. But, I think I just found out the correct way to do it std::transform (vect.begin(), vect.end(), std::back_insterter(numVect), (arg1->*&getNumber)()); – polapts Jul 04 '13 at 11:34
  • 2
    Great. Now forget you ever knew that, and future maintainers of your code will like you more. :) Anyway, feel free to post your own answer if you get a fully working version coded up using the same names as in your question. – John Zwinck Jul 04 '13 at 11:36
  • 1
    Oh well. I personally think Phoenix has lot's of things going for it. At least until we can have polymorphic lambdas. – sehe Jul 04 '13 at 23:06

2 Answers2

2

As you note above, the way to do this with Phoenix is with phoenix::bind or with ->* as you do above:

#include <vector>
#include <boost/phoenix/core.hpp>
#include <boost/phoenix/operator.hpp>
#include <boost/range/algorithm/transform.hpp>

class myClass
{
    int i;

public:
    int getNumber() { return i; }
    void setNumber(int j) { i = j; }
};

int main()
{
   std::vector<myClass*> vect;
   std::vector<int> numVect;

   using boost::phoenix::arg_names::arg1;
   boost::transform(vect,
                    std::back_inserter(numVect),
                    (arg1->*&myClass::getNumber)());
}

Phoenix can be complicated, and bind expressions are some of the most convoluted and contrived of Phoenix's syntactic contortions, but in all honestly, this one doesn't seem that bad.

C++14's polymorphic lambdas will obviate much of Phoenix, by the way.

Eric Niebler
  • 5,927
  • 2
  • 29
  • 43
  • +1 This is a nice display of the 'puritan' way (including `back_inserter` :)). However, I'd always prefer `bind` or `function<>` of some kind (I show using `phoenix::lambda` in my answer) – sehe Jul 04 '13 at 23:10
  • PS. The real puritan way would, of course, be `std::mem_fn(&myClass::getNumber)`... but that wouldn't do justice to the tags – sehe Jul 04 '13 at 23:11
0

I'd use

std::transform (vect.begin(), vect.end(), numVect.begin(), phx::bind(&myClass::getNumber, arg1));

Or, if you wanted nicer syntax:

auto getNumber = phx::lambda [ phx::bind(&myClass::getNumber, arg1) ];
std::transform (vect.begin(), vect.end(), numVect.begin(), getNumber(arg1));

Demo:

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

namespace phx = boost::phoenix;

struct myClass
{
   int i;

   int getNumber() const { return i; }
   void setNumber(int j) { i = j; }
};

using namespace boost::phoenix::arg_names;
static const auto getNumber = phx::lambda [ phx::bind(&myClass::getNumber, arg1) ];

int main()
{
   const std::vector<myClass*> vect { new myClass{1}, new myClass{2}, new myClass{42} };
   std::vector<int> numVect(vect.size());

   // puritan/standard version:
   std::transform (vect.begin(), vect.end(), numVect.begin(), std::mem_fn(&myClass::getNumber));

   // just bind:
   std::transform (vect.begin(), vect.end(), numVect.begin(), phx::bind(&myClass::getNumber, arg1));

   // using more natural syntax
   std::transform (vect.begin(), vect.end(), numVect.begin(), getNumber(arg1));

   for(auto i : numVect)
       std::cout << i << " ";
}
sehe
  • 374,641
  • 47
  • 450
  • 633