7

I have read many posts and answers about pointers to non-static member functions, but none looks able to solve my problem.
So I have created a short example to replicate my issue here: even if this example could be "solved" in different ways, for the final software it is important to keep the structure like in the example, thanks.

This is the header of the class "Funcs.h":

class Funcs
{
private:
  double a = 1, b = 2;

public:
  Funcs();
  ~Funcs();
  double Fun1(double X);
  double solver(double X0);
  double aaa(double(*fun)(double), double x0);
};

This is the cpp of the class "Funcs.cpp":

#include "Funcs.h"

using namespace std;

Funcs::Funcs()
{
}

Funcs::~Funcs()
{
}

double Funcs::Fun1(double X) {
  double f1 = a*X;

  return f1;
}

double Funcs::solver(double X0)
{
  double result;

  result = aaa(Fun1, X0);
  return result;
}

double Funcs::aaa(double(*fun)(double), double x0)
{
  return fun(x0);
}

And Finally this is the main "main.cpp":

#include <iostream>
#include "Funcs.h"

using namespace std;

int main() {
  double x0=1;
  double result;
  Funcs funcs;

  result = funcs.solver(x0);
  cout << result << endl;

  return 0;
}

The error is in the method Funcs::solver when I call "result = aaa(Fun1, X0);" because I can't use a pointer to Fun1 because it is a non-static member. At the same time I can't make it static, otherwise the variable "a" could not be seen inside the static method.

Thanks in advance for your help.

Mattia
  • 135
  • 3
  • 13
  • So what exactly can you change? Something is going to have to as a member function is not the same as a regular function. – NathanOliver Jul 26 '17 at 15:59
  • @NathanOliver , for what I have seen in other posts, i should change how I pass the first parameter to the function "aaa(Fun1, X0);", that is the same the compilator ask, but everything I have tried does not work... – Mattia Jul 26 '17 at 16:03
  • 1
    You can't convert a member function pointer into a regular function pointer. You either have to change what `aaa` accepts or make `Fun1` static to use `aaa` as is. – NathanOliver Jul 26 '17 at 16:05

4 Answers4

6

The problem is that you're trying to pass a pointer to a member function while a pointer to either a non-member function or a static member function is expected. And those are different types.

Here "fun" is a pointer to function: double(*fun)(double).

And here it's a pointer to a member function of class Funcs: double(Funcs::*fun)(double)

So here's how you can modify your code to make it work.

class Funcs
{
  // all the rest is the same
  double aaa(double(Funcs::*fun)(double), double x0);
};

double Funcs::solver(double X0)
{
  // ...
  result = aaa(&Funcs::Fun1, X0);
  // ...
}

double Funcs::aaa(double(Funcs::*fun)(double), double x0)
{
  return (this->*fun)(x0);
}

See live example at Coliru.

This may be a fine way to go if you want to deliberately limit your method aaa to accept only Funcs member functions as fun. If you'd also like to pass the non-member functions or e.g. lambdas to aaa, consider using std::function instead.

Vasiliy Galkin
  • 1,894
  • 1
  • 14
  • 25
  • Thanks Vasily, your code works well! The only "problem" is that doing like that, I should implement a member function `aaa` for every class needs to use it, because that in my final code will be a general mathematic function that can be used for a lot of things. I can do it, but it is a bit a waste of time... Do you have an idea for avoiding this? – Mattia Jul 26 '17 at 20:30
  • I'm not entirely sure I fully understood your requirements. Let me clarify: you need your function `aaa` to accept the member functions of several classes, e.g. `Foo::func1`, 'Bar::func`. Is it correct understanding? – Vasiliy Galkin Jul 26 '17 at 20:42
  • 1
    In case it's like that, then you have several options, each of them presumes that you move `aaa` out of your class. 1) You may use `std::function` as suggested in the answer - see [example 1](http://coliru.stacked-crooked.com/a/50fe768464a604b0); 2) you may use perfect forwarding - see [example 2](http://coliru.stacked-crooked.com/a/8c020793517cad43); 3) if you want to limit the argument only by the methods of the classes, you may still use the similar signature as proposed by the answer + template, see [example 3](http://coliru.stacked-crooked.com/a/347525dc86609e68). – Vasiliy Galkin Jul 26 '17 at 20:58
  • Each alternative has its pros and cons, the choice is yours ;) – Vasiliy Galkin Jul 26 '17 at 20:58
  • Thanks, you have completely understood my needs. I would prefer the first option, but just because looks a bit easier. Now I have added a new function 'bbb' with a call from the previous 'aaa', but it creates a problem because the argument is again the pointer to the same function, but now it is not passed from the class. Can you have a look at [this code](http://coliru.stacked-crooked.com/a/239e991b95a964b7)? – Mattia Jul 26 '17 at 22:16
  • [This](http://coliru.stacked-crooked.com/a/c4588f63e17d94c0) should be works – joseAndresGomezTovar Nov 04 '21 at 09:45
4

Your problem is that pointer-to-function is not the same as pointer-to-member-function. Read this for more info and this for clean way to write pointer-to-member-functions. If you need to keep this structure, make aaa a static or non-member function that takes everything it needs as arguments, or change the first argument of aaa to take a double(Funcs::*)(double) rather than a double(*fun)(double). You can even overload aaa to support both uses.

patatahooligan
  • 3,111
  • 1
  • 18
  • 27
2

Actually Funcs::Fun1 is not double(*)(double).

Any non-static method has this signature: return_type(*)(class_type* this, arguments...)

Lets look at exact types:

//first argument of `aaa` has type double(*)(double)
double aaa(double(*fun)(double), double x0);

double Funcs::Fun1(double X) {
  double f1 = a*X;

  return f1;
}

// Fun1 has type double(Funs::*)(double)
// i.e it's a method of Funs and it takes (implicitly) first argument
// which is `this` pointer

// so that how `aaa` must  look like
double aaa(double(Funs::*fun)(double), double x0)
{
    // special sytax
    *this.*fun(x0);
}

// and that how `solver` looks like
double Funcs::solver(double X0)
{
  double result;

  // get pointer to method
  result = aaa(&Funs::Fun1, X0);
  return result;
}

If you are not familar with pointers to methods - check this

  • You missed the parentheses around *this.*fun, i.e., (*this.*fun)(x0). I'm curious how u were satisfied with submitting an answer without even testing it in a real compiler. – user5280911 Jan 19 '19 at 20:00
0

I am still new to c++, but the solution I know is to have a static function acting as a delegate. https://learn.microsoft.com/ru-ru/windows/win32/learnwin32/managing-application-state-

///FOLLOW THE LINK FOR FULL CODE to understand what i am talking about :)

Take a look at how win32 API provides a static callback function acting as a delegate. in short, function takes number of inputs, and the last parameter is the class the caller passed as a void pointer.

static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        DERIVED_TYPE *pThis = NULL;

        if (uMsg == WM_NCCREATE)
        {
            // routine to recast back pointer to your class type so you have access to your local members with "This"
            CREATESTRUCT* pCreate = (CREATESTRUCT*)lParam;  
            pThis = (DERIVED_TYPE*)pCreate->lpCreateParams;
            SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pThis);

            pThis->m_hwnd = hwnd;
        }

Take a look at how lParam is being cast back to DERIVED_TYPE which is a type of your class and pThis acts as normal this and gives you the access to class members.

Anton Stafeyev
  • 761
  • 1
  • 7
  • 20