21

I'm trying to setup a function pointer that is set during execution based on a set of user parameters. I would like to have the function pointer point to a non-static member function but I can't find how to do it.

The examples I've seen say this can only be done with static member function only or use global variables in straight C.

A simplified example follows:

    class CA
    {
    public:
        CA(void) {};
        ~CA(void) {};
        void setA(double x) {a = x; };
        void setB(double x) {b = x; };

        double getA(const double x) {return x*a; };
        double getB(const double x) {return x*b; };

        void print(double f(const double), double x) {
            char cTemp[256];
            sprintf_s(cTemp, "Value = %f", f(x));
            std::cout << cTemp;
        };

    private:
        double a, b;
    };

The implementation part is

CA cA;
cA.setA(1.0);
cA.setB(2.0);

double (*p)(const double);

if(true) {
    p = &cA.getA;  //'&' : illegal operation on bound member function expression
} else {
    p = cA.getB;  //'CA::getB': function call missing argument list; use '&CA::getB' to create a pointer to member
                  //'=' : cannot convert from 'double (__thiscall CA::* )(const double)' to 'double (__cdecl *)(const double)'
}

cA.print(p, 3.0);

So how do I get p to point to either 'getA' or 'getB' so that it is still useable by 'print'.

From what I have seen, the suggestions are to use boost or std::bind but I've had no experience with either of these. I'm hoping that I don't need to dive into these and that I'm just missing something.

Compiler MSVC++ 2008

3 Answers 3

20

Don't forget that a member function accepts an implicit this parameter: therefore, a member function accepting a double can't be the same thing as a non-member (free) function accepting a double.

// OK for global functions
double (*p)(const double);

// OK for member functions
double (CA::*p)(const double);

Also, the way you invoke them is different. First of all, with member functions, you need an object to invoke them on (its address will eventually be bound to the this pointer in the function call). Second, you need to use the .* operator (or the ->* operator if you are performing the call through a pointer):

p = &CA::getA;
CA cA;
(cA.*p)();

Consistently, you will have to change your definition of function print():

#include <iostream>

void print(double (CA::*f)(const double), double x) 
{
    // Rather use the C++ I/O Library if you can...
    std::cout << "Value = " << (this->*f)(x);
};

So finally, this is how you should rewrite your main() function:

int main()
{
    CA cA;
    cA.setA(1.0);
    cA.setB(2.0);

    double (CA::*p)(const double);

    if (true)
    {
        p = &CA::getA;
    } 
    else {
        p = &CA::getB;
    }

    cA.print(p, 3.0);
}
Sign up to request clarification or add additional context in comments.

7 Comments

Function print needs to change too, to receive proper function pointer.
So I'm confused on p = &CA::getA; Doesn't this mean that you're trying to access a static member function?
@PartTimeUser: No, it does not. It's the syntax for taking the address of a member function.
Groovy. In a lot of the examples I perused I was getting hung up on the 'p=&CA::getA' section. This works great but I'm still confused on the it. If I add
double (CA:*p)(const double); needs to be double (CA::*p)(const double);
|
9

Compilation Issue

This answer focuses on the compilation issue presented in the question. I would not recommend implementing this as a solution.

Pointers to member functions are best dealt with with typedefs and a macro.

Here's the macro for calling a member function:

#define CALL_MEMBER_FN(object, ptrToMember)  ((object).*(ptrToMember))

Source: [33.6] How can I avoid syntax errors when calling a member function using a pointer-to-member-function?, C++ FAQ.

This saves you having to remember the ugly (object).*(ptrToMember) syntax any time you wish to call a member function by pointer.

In your class, declare a typedef called CAGetter, this will make variable declaration much simpler:

class CA
{
public:    
    typedef double (CA::*CAGetter)(const double x);

Then you can declare your print() function quite simply:

    void print(CAGetter f, double x)

The body is also simple, clear and concise:

    {
        std::cout << "value = " << CALL_MEMBER_FN(*this, f)(x) << '\n';
    }

Sample usage:

CA a;
a.setA(3.1);
a.setB(4.2);

// Using a variable...
CA::CAGetter p = &CA::getA;
a.print(p, 1);

// without a variable
a.print(&CA::getB, 1);

// Calling the functions from outside the class...
std::cout << "From outside (A): " << CALL_MEMBER_FN(a, p)(10) << std::endl;
std::cout << "From outside (B): " << CALL_MEMBER_FN(a, &CA::getB)(10) << std::endl;

Design Issue

Passing a pointer to a member function into a method of an instance of the same class is a design smell (you wouldn't normally pass a member variable to a method, this is no different). There is not enough information in this question to address the underlying design issue but this problem could probably be solved with separate print() methods, a member variable or with inheritance and polymorphism.

1 Comment

Great explanation, but your code smell claim is equivalent to suggesting that one should never use their hands to point at their own body because they are part of the same individual unit.
0

You can either use pointer to method:

class CA
{
    public:
        typedef double (CA::*getter)( double );
        CA(void) {};
        ~CA(void) {};
        void setA(double x) {a = x; };
        void setB(double x) {b = x; };

        double getA(const double x) {return x*a; };
        double getB(const double x) {return x*b; };

        void print(getter f, double x) {
            char cTemp[256];
            sprintf(cTemp, "Value = %f", (this->*f)(x));
            std::cout << cTemp;
        };

    private:
        double a, b;
};

int main()
{
    CA cA;
    cA.setA(1.0);
    cA.setB(2.0);

    CA::getter p;

    if(true) {
            p = &CA::getA;  
    } else {
            p = &CA::getB; 
    cA.print( p, 3.0 );
}

Or use boost::bind

class CA
{
    public:
        typedef boost::function<double( double )> getter;
        CA(void) {};
        ~CA(void) {};
        void setA(double x) {a = x; };
        void setB(double x) {b = x; };

        double getA(const double x) {return x*a; };
        double getB(const double x) {return x*b; };

        void print(getter f, double x) {
            char cTemp[256];
            sprintf(cTemp, "Value = %f", f(x));
            std::cout << cTemp;
        };

    private:
        double a, b;
};

int main()
{
    CA cA;
    cA.setA(1.0);
    cA.setB(2.0);

    CA::getter p;

    if(true) {
            p = boost::bind( &CA::getA, &cA, _1 );
    } else {
            p = boost::bind( &CA::getB, &cA, _1 );
    }
    cA.print( p, 3.0 );
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.