1

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?

Tryer
  • 3,580
  • 1
  • 26
  • 49
  • 2
    The `print_array_of_length5` function take a pointer to a non-member function. – Ghasem Ramezani Sep 10 '21 at 15:20
  • 2
    You cannot call a non-`static` member function without an instance and there is no instance available in `print_array_of_length5` - you have to rethink your entire approach – UnholySheep Sep 10 '21 at 15:23

2 Answers2

4

You need another overload for print_array_of_length5 in order to pass a member function pointer:

template<typename T>
void print_array_of_length5(int (T::*fnptr)(int index), T& obj)
{
    for(int i = 0; i < 5; ++i)
    {
        printf("%d ", (obj.*fnptr)(i));
    }
}

int main()
{
    SIMPLE smpl;
    print_array_of_length5(&SIMPLE::retval, smpl);
}
Ghasem Ramezani
  • 2,683
  • 1
  • 13
  • 32
  • I tested this approach and this works. However, one would need to replicate the code inside of print_array_of_length5 twice -- one with a single argument and another with two arguments, don't you think? In @NathanOliver's answer, it appears only one function needs to be maintained. – Tryer Sep 10 '21 at 15:35
  • In speak of maintenance: The @NathanOliver's implies the need to type validations, which is enough to take things complex. And BTW, the usage of the function in the question is not clear. – Ghasem Ramezani Sep 10 '21 at 15:40
2

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);
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • I worked further with this answer trying to implement this in my more complicated project where I have an `OUTER` class in one of whose method a different `INNER` class object's method should be pass as a function pointer. I am running into a compilation issue there. Would it be possible for you to take a look at this link which shows the compiler error to suggest a way out? https://godbolt.org/z/rG1oc86z5 If that is too much to ask, I can understand. I will post a new question on SO. – Tryer Sep 10 '21 at 17:20
  • 1
    @Tryer You forgot to give the function parameter a name in the definition: https://godbolt.org/z/MK3sGx1hY – NathanOliver Sep 10 '21 at 17:23
  • Ah yes. Sorry I am extremely new to templates, etc. Thank you again. – Tryer Sep 10 '21 at 17:27