Pawel
Pawel

Reputation: 43

C++ pointer to a function

In my code I would like to call different functions by the same name. So I used pointers, and I did work with static functions, now I would like to do the same with non-static functions and it doesn't work at all.

class Amrorder
:   {
public:
   ....
    void (*fkt)(real&, const real);
    void fktAcPulse(real &rhoRef, const real y);
    void fktAcPulseSol(real &rhoRef, const real y);
...
}

void Amrorder::initData(a)
{
...
 switch(method){
    case 2://
      Amrorder::fkt=&Amrorder::fktAcPulse;
      break;
    case 222://
      Amrorder::fkt=&Amrorder::fktAcPulse1d;
      break;
    }
...
  for(int i=0; i<ng; ++i){ 
    Amrorder::fkt(rhoRef, yRef);
    ...
  }
...
}

The code is quiet big so I hope the part above is enough to understand what I want to do.

Thanks for your time!

Upvotes: 1

Views: 574

Answers (3)

leemes
leemes

Reputation: 45725

The type of fkt declares a function pointer to a free-standing function or a static member function. But you want to assign a non-static member function pointer to it. So fkt needs to be of the type of a non-static member function pointer of class Amrorder. That type is spelled

void (Amrorder::*fkt)(real&, const real);
//    ^^^^^^^^^^

When invoking a function pointer to a non-static member function, you need to specify on which object you want the member to be called (which normally defaults to this when calling a member function directly with its name).

The syntax for this is quite strange. It requires another pair of parentheses and depends on wether you call it on a pointer or an object itself:

(object.*functionPointer)(arguments);
(pointer->*functionPointer)(arguments);

So if you just want to call the function on the this pointer, you need to write

(this->*fkt)(rhoRef, yRef);

(Note that you don't need to specify the class in your code everywhere. Amrorder:: can be removed in front of every function name inside the definition of a member function of the same class.)

Upvotes: 0

Barry
Barry

Reputation: 303780

It doesn't work because your fkt has type:

void (*)(real&, const real);

and you're trying to assign it to, e.g., &Amrorder::fktAcPulse, which has type:

void (Amrorder::*)(real&, const real);

Notice the difference. The latter is a pointer-to-member function, not just a pointer to function. These have different semantics. A pointer to function can just be called (e.g. fkt(a, b)), but a pointer to member function needs to be called on an object (e.g. (obj.*pm)(a, b)).

For simplicity, since you probably just want "something that I can call with a real& and a const real", you may want to consider the type-erased function object: std::function:

std::function<void(real&, const real)> fkt;

This can be initialized with any callable that matches the arguments, so you can assign it to a free function:

void foo(real&, const real) { ... }
fkt = foo;

A static member function:

struct S { static void bar(real&, const real) { ... } };
fkt = &S::bar;

Or a member function, as long as its bound:

fkt = std::bind(&Amrorder::fktAcPulse, this);
fkt = [this](real& a, const real b){ return this->fktAcPulse(a, b); };

The key is that you need an instance of Amrorder to call fktAcPulse, and using std::function lets you use either std::bind or a lambda to store that instance in with the functor itself.

Upvotes: 1

ravenspoint
ravenspoint

Reputation: 20596

When you call a non-static method of a class, the compiler needs to know which instance of the class you want to execute against. So there is a hidden parameter in the call, which is a pointer to the instance.

So you need to write something like this:

Amrorder::fkt=bind( &Amrorder::fktAcPulse, this );

Upvotes: 0

Related Questions