Search code examples
c++function-pointerspointer-to-member

Difficulty in passing function pointer of a class member function


In trying to implement a suggested answer here in my own context, I am running into a compilation error.

Consider code:

#include <iostream>

class SIMPLE {
public:
    SIMPLE() { for (int i = 0; i < 5; i++) val[i] = 5; };
    int retval(int index) { return val[index]; }
private:
    int val[5];
};

void print_array_of_length5(int (*fnptr)(int index)){
    for (int i = 0; i < 5; i++)
        printf("%d ", fnptr(i));
}

int global_array[5] = { 0, 1, 2, 3, 4 };
int global_function(int index){
    return global_array[index];
}

int main(){
    print_array_of_length5(&global_function);//Works fine.
    int (SIMPLE::*p)(int) = &SIMPLE::retval;//Following method suggested in the answer above
    class SIMPLE smpl;
    print_array_of_length5(smpl.*p);//Compile error: a pointer to a bound function may only be used to call the function
}

The function works when supplied with the address of a global function. It does not work when passed smpl.*p analogous to the method suggested. How should one fix this error?


Solution

  • You can't pass a non-static member function pointer as a regular function pointer. Member functions have access to the this pointer, and the way they get that is via an invisible implicit function parameter. You need to have the object on which to call the function, and the function itself, be bound together, which a function pointer simply can't do.

    What we can do is make print_array_of_length5 a function template, and allow it to take any type of callable. That would give you something like this:

    template <typename Function>
    void print_array_of_length5(Function func){
        for (int i = 0; i < 5; i++)
            printf("%d ", func(i));
    }
    

    To call it with a non-static member function, you can use a lambda expression, or std::bind(), like this:

    SIMPLE smpl;
    print_array_of_length5([&smpl](int foo){ return smpl.retval(foo); });
    
    using namespace std::placeholders;
    SIMPLE smpl;
    auto func = std::bind(&SIMPLE::retval, &smpl, _1);
    print_array_of_length5(func);