Pointer to Member Function (I know; I'm not supposed to)

I'm trying to set up an equations solver using the GSL root finder routines. In short, I have various combinations of equations that are functions of two variables (temperature & density). I've already coded these equations and have proven them to be accurate. I'm now attempting to calculate the required variables for various combinations of their results (pressure, specific enthalpy, specific entropy, etc).

In my first attempt I've run into a problem with the function pointers utilized by GSL for solving (https://www.gnu.org/software/gsl/manual/html_node/Providing-the-function-to-solve.html). The pertinent parts of the code are below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
class State
{
    public:
        State();    // Constructor
        virtual ~State();   // Destructor

        // Simple Set functions - Probably won't be used much.
        /* code here */

        // Complex Set Functions
        /* Other set functions */

        //This is the one causing problems
        void setState_PT(num_t P, num_t T); // Sets the state on the given Pressure & Temperature

    protected:
        // Helper functions and structures required set functions
        struct helpPressureStruct
        {
            num_t T; // Temperature
            num_t desPress; // desired pressure
        };

        double helpPressurePT(double P, void* params);

    private:
        num_t temperature;
        num_t density;
        num_t pressure;
};

void State::setState_PT(num_t P, num_t T)
{
    if (P == helmholtz::psat(T))
    {
        setState_Tsat(T);
        return;
    }

    int status;
    int iter = 0, max_iter = 100;
    const gsl_root_fsolver_type* solver_t;
    gsl_root_fsolver* s;
    double r = 0;
    double rhomin = 0.0, rhomax = 2000;
    gsl_function F;

    struct helpPressureStruct params;
    params.T = T;
    params.desPress = P;

    F.function = &helpPressurePT;
    F.params = &params;

    solver_t = gsl_root_fsolver_brent;
    s = gsl_root_fsolver_alloc(solver_t);
    gsl_root_fsolver_set(s, &F, rhomin, rhomax);

    do
    {
        iter++;
        status = gsl_root_fsolver_iterate(s);
        r = gsl_root_fsolver_root(s);
        rhomin = gsl_root_fsolver_x_lower(s);
        rhomax = gsl_root_fsolver_x_upper(s);
        status = gsl_root_test_interval(rhomin, rhomax, 0, 0.001);
    }
    while (status == GSL_CONTINUE && iter < max_iter);

    gsl_root_fsolver_free(s);

    /* Finish setting the state using results from above */

    return;
}

double State::helpPressurePT(double P, void* params)
{
    struct helpPressureStruct* pHelp = (struct helpPressureStruct*) params;
    num_t T = pHelp->T;
    num_t desPress = pHelp->desPress;

    return helmholtz::p(T, P) - desPress;
}


|52| error: ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function. Say ‘&State::helpPressurePT’ [-fpermissive]

However, making that line:
F.function = &State::helpPressurePT;
produces
error: cannot convert ‘double (State::*)(double, void*)’ to ‘double (*)(double, void*)’ in assignment

I understand this is a pointer to member function, which doesn't behave like a normal function pointer. Unfortunately, the typical searches are turning up answers that are more difficult to understand than the original error. In any case, how would you kind folks recommend getting this function over to GSL for solving?
There is absolutely nothing wrong with using function pointers.

The problem here is that you are dealing with two different kinds of pointers:
 • gsl_function is a pointer-to-non-member-function
 • helpPressurePT is a pointer-to-member-function

They are incompatible. What you need is a kind of thunk to call the member function from a non-member function.

Here is an example of doing that to enumerate the top-level windows in Windows:
http://www.cplusplus.com/forum/general/170775/#msg851518

Notice how the static member function (which is the same as calling a non-member function) has an extra piece of data passed to it — the lParam, which is actually the address of the object — which the function uses to reconstruct a call to the member function.

I have not used the GSL, but it appears you could use the params argument to do the same thing. GSL would call your non-member (or static member) function with a params value you provide that is actually the address of your object. The non-member-function or static-member-function then reconstructs the call to call a member function of the specific object, which, of course, has all the information needed to perform the desired calculation.
https://www.gnu.org/software/gsl/manual/html_node/Providing-the-function-to-solve.html

Hope this helps.
Could you please spell out how to do this? In particular, I'm trying to wrap myself around the lParam in your example. What is that actually? I'm pretty new to working with some of these features. I greatly appreciate your assistance.
Last edited on
This is a quick and dirty example of what @Duthomas suggested. I have not compiled it, and there might be some mistakes, but you should be able to see how it is supposed to work.

1
2
3
4
5
6
struct helpPressureStruct
{
    num_type T;
    num_t desPress;
    State* statePtr;
};


1
2
3
4
5
6
7
    helpPressureStruct params;  // don't need keyword "struct" here in C++
    params.T = T;
    params.desPress = P;
    params.state = this;

    F.function = &globalHelpPressurePT;
    F.params = &params;


1
2
3
4
5
double globalHelpPressurePT(double P, void* params)  // NOT a member function.
{
    helpPressureStruct* pHelp = (helpPressureStruct*) params;
    return pHelp->statePtr->helpPressurePT(P, params);
}
Thank you, guys! That worked wonderfully. Now I have to figure out how to make the equations actually converge to the right value.
I got to messing around a bit and discovered that I didn't need the typical member function, only the static member function.

1
2
3
4
5
6
struct helpPressureStruct
{
    num_type T;
    num_t desPress;
    State* statePtr;
};


1
2
3
4
5
6
7
    helpPressureStruct params;  // don't need keyword "struct" here in C++
    params.T = T;
    params.desPress = P;
    params.state = this;

    F.function = &globalHelpPressurePT;
    F.params = &params;


The major changes occurred here.
1
2
3
4
5
double State::helpPressurePT(double P, void* params)  // declared static in header
{
    helpPressureStruct* pHelp = (helpPressureStruct*) params;
    return helmholtz::p(pHelp->T, P) - pHelp->desPress;
}


For anyone that stumbles across this, I hope the changes help.
Well, if you are calling a static member function, you no longer need to keep a State object, so you can get rid of the statePtr (1st snippet, line 5; 2nd snippet, line 4) that I added for that specific reason.

And if you are getting rid of the global-scoped globalHelpPressurePT function, you need to change line 6 in the 2nd code snippet.
Topic archived. No new replies allowed.