zuuz
zuuz

Reputation: 879

member function pointers c++

I've looked at the top answers c++ to Visitor pattern and to pointers to member functions; but I still cannot get how the following (rather simple) scenario should be designed.

In a basic example, I want to have an optimizer class. Given a member function of another class, it find some optimal value. Something like this:

class Optimizer{
    public:
        typedef double (*Func1d)(double);
        typedef double (*Func2d)(double,double);
        void Optimize1d(Func1d* f1Ptr, double& x);
        void Optimize2d(Func2d* f2Ptr, double& x, double& y);
};

and two example classes:

class A {
    double A1d(double x){return x;}
};

class B{
    double B2d(double x, double y){return x+y;}
};

and the main function, which I would like to be able to use as follows:

void main()
{
    Optimizer opt;
    double xA_opt, xB_opt, yB_opt;
    opt.Optimize1d(&A::A1d,xA_opt);
    opt.Optimize2d(&B::B2d, xB_opt, yB_opt);
}

But still, I can't get it to work. I don't want the optimizer to directly hold pointers to objects of type A and B; because then he needs to be familiar with these objects.

I hope this question makes sense. Thanks!

Upvotes: 1

Views: 130

Answers (2)

Chris Drew
Chris Drew

Reputation: 15334

The problem is that typedef double (*Func1d)(double); is not a member-function-pointer but just a plain function-pointer.

If you used a real member-function-pointer, the function would also have to have an instance of A or B which you say you don't want.

If you can't make A1d and B2d static the other options are to make your Optimize1d and Optimize2d template functions taking a templated functor:

template<typename F>
void Optimize1d(F f1, double& x);
template<typename F>
void Optimize2d(F f2, double& x, double& y);

or a std::function:

void Optimize1d(std::function<double(double)> f1, double& x);
void Optimize2d(std::function<double(double, double)> f2, double& x, double& y);

Both can be called with a lambda capturing an instance of A or B:

A a;
B b;
opt.Optimize1d([&a](double x){return a.A1d(x); }, xA_opt);
opt.Optimize2d([&b](double x, double y){return b.B2d(x, y); }, xB_opt, yB_opt);

Edit: If you don't have C++11 you could define your own functor using a class which defines an operator() instead of a lambda. The class will have to store a pointer or reference to an instance of A or B in a member variable:

struct A1d {
    A* a;
    A1d(A& a) : a(&a) {}
    double operator()(double x) { return a->A1d(x); }
};

You can then construct an instance of this class and pass it to the templated optimize functions:

A1d a1d(a);  
opt.Optimize1d(a1d,xA_opt);

Live demo.

perhaps you could even make your A or B classes functors themselves by adding an operator() function to them?

Upvotes: 2

Chris Beck
Chris Beck

Reputation: 16204

The problem in the above code is that in C++, pointer-to-member functions are a distinct type, incompatible with "regular" function pointers.

This typedef

typedef double (*Func1d)(double);

is legal in both C and C++ code, and you can use C-style "free" functions with this type.

But at this line in your main function:

opt.Optimize1d(&A::A1d,xA_opt);

you are trying to pass a pointer to member function as a Func1d and that can't be done. For one thing, you can't invoke a pointer to member function without a pointer to an object of that type as well, and you would have to pass that also.

The simplest thing is to include header <functional> and use std::function<double(double)> for this. (Assuming you have C++11, otherwise you could use boost::function.)

There are other things you could do like use virtual member dispatch as suggested in comments. (IMO that's a little less elegant.)

You could also make the optimize functions be template functions, and accept an object of the templated type etc. etc. But really std::function is the way to go here, it will handle all those details for you.

Upvotes: 2

Related Questions