std::transform with virtual call operator throws "global functions do not have 'this' pointers"

285 views Asked by At

PayOff is an abstract base class and CallPayOff and PutPayOff derive from it. The call operator is defined as a pure virtual function in base class and CallPayOff and PutPayoff provide their own implementations.

vector<PayOff*> v;
v.push_back(new CallPayOff(20));
v.push_back(new PutPayOff(20));
vector<double> payVals;
payVals.reserve(v.size());
transform(v.begin(), v.end(), back_inserter(payVals),  bind2nd(mem_fun(&PayOff::operator()),this));

Call operator is defined as:

class PayOff
{
public:
    virtual double operator()(double spot)const = 0;
    virtual ~PayOff(){}
};

Can anyone please take a look? Boost/C++11 is not an option.

4

There are 4 answers

0
Mike Seymour On BEST ANSWER

You don't say what you expect the transform to do; presumably it's to invoke each PayOff object on some value. In that case the functor should be:

bind2nd(mem_fun(&PayOff::operator()),some_value)

or, for those not stuck in the past,

[=](PayOff* p){(*p)(some_value;}}

or

bind(&PayOff::operator(), _1, some_value);

You are instead trying to bind to this which, in a global function, doesn't exist. In a member function, it would exist, but wouldn't make sense as an argument to a functor that expects a double.

2
David Rodríguez - dribeas On
transform(v.begin(), v.end(), payVals.begin(),  
          bind2nd(mem_fun(&PayOff::operator()),this));

The names in the call to transform must be looked up and resolved at the place where the call takes place. Which according to your comment is main. Inside main, you cannot use this.

If you have a C++11 compiler you can opt to either use a lambda or std::bind:

std::transform(std::begin(v), std::end(v),
               std::begin(payVals),
               [](PayOff* p) { (*p)(value); });
std::transform(std::begin(v), std::end(v),
               std::begin(payVals),
               std::bind(&Payoff::operator(), _1, value); // using std::placeholders::_1

In C++03 you can use boost::bind instead of std::bind or if that is not available you can create your own functor or adapter functor that will call operator() on the argument.

0
Zac Howland On

If you are calling transform from your main function, this does not exist.

0
user2672165 On

It looks as you should supply a double as follows (not a pointe as suggested above):

const double spot(99.);
transform(v.begin(), v.end(), payVals.begin(),  bind2nd(mem_fun(&PayOff::operator()),spot));

PS I have not checked your syntax but essentially this is how to do in pre-c++11 code.