3

I'm wondering if there's a way in standard C++ (it seems this is not supported but perhaps I didn't look hard) to declare a pointer to any class' member function with the same signature. For example, X and Y have echoX and echoY methods with the same signature

class X{
  int val;
public:
 int echoX(int v)  {
 val = v;
 return v; }
   int getValue() const { return val; }
};

class Y{

   int val;
   public:
   int echoY(int v)  {
   val = v;
   return v;
   }
   int getValue() const { return val; }
};

Some C++ implementations allow this functionality via extensions (e.g VCL makes use of the __closure keyword).

typedef int (__closure *IntFunPtr)(int);

Now, it's trivial to write a function that is able to call either X::echoX or Y::echoY

void CallObjectMethod(IntFunPtr fPtr, int val){

    fPtr(val);//this can call any member method that accepts an int and returns an int
}


X x, x1;
CallObjectMethod(&x.echoX,4);
CallObjectMethod(&x1.echoX,20);

Y y, y1;
CallObjectMethod(&y.echoY,10);
CallObjectMethod(&y1.echoY,15);

This functionality can be useful for implementing event handlers, among other things.

Thank you

dsp_user
  • 2,061
  • 2
  • 16
  • 23
  • The standard C++ approach today would be to accept a general functor (either by making the whole thing a template, or using `std::function`), and letting the caller pass whatever callable they want as an argument. This also solved the problem you have hidden, of having to pass the actual pointer to the object. – StoryTeller - Unslander Monica Dec 21 '17 at 11:32
  • And this is a possible duplicate, I'd say https://stackoverflow.com/questions/31634887/c-pointer-to-member-function-replacement-for-closure – StoryTeller - Unslander Monica Dec 21 '17 at 11:35
  • Well, ideally we should be able to do this even from a simple function (*std::function* does much more but Samer's solution seems sufficient for this). Thanks – dsp_user Dec 21 '17 at 12:27

2 Answers2

5

"For example, X and Y have echoX and echoY methods with the same signature"

Afaik they dont have the same signature, they have an implicit first argument to the class instance. Usually you would choose an std::function to get rid of the first argument.

#include <functional>

class X { public: int echoX(int v) {return v; } };

class Y { public: int echoY(int v) {return v; } };

typedef std::function<int(int)> IntFunction;

int echo(IntFunction func, int v)
{
    return func(v);
}

int main()
{
    int v = 5;
    X x;
    Y y;
    int a = echo(std::bind(&X::echoX, x, std::placeholders::_1), v);
    int b = echo(std::bind(&Y::echoY, y, std::placeholders::_1), v);
}
lars
  • 658
  • 4
  • 11
2

You could create a generic templated function which accepts the signature you are interested in, pass in the instance of the object and the pointer to the member function. For example:

template<typename T>
void CallObjectMethod(int(T::*func)(int), T& obj, int val)
{
    cout << (obj.*func)(val);
}

Now to call it like you mentioned in your example:

X x, x1;
CallObjectMethod(&X::echoX, x, 10);
CallObjectMethod(&X::echoX, x1, 20);

For object Y you could do something like:

Y y, y1;
CallObjectMethod(&Y::echoY, y, 10);
CallObjectMethod(&Y::echoY, y1, 20);
Samer Tufail
  • 1,835
  • 15
  • 25
  • This is indeed a very elegant solution, kind of like a templated version of dynamic functions). BTW, I thought of using simple static functions and passing an object instance but this is better. – dsp_user Dec 21 '17 at 12:16
  • Thank's for posting this. It is similar to a problem I'm trying to solve and looks like a good solution. –  Mar 04 '19 at 16:56
  • 2
    This is not a solution... This is not a generic function pointer but a template-simplification to write less code for multiple distict function-pointers. It works i this simple exapmle where you could as well call the functions on the object itself. But you can still not write a function that takes different types of objects and an associated member-funtion-ptr. Any generic function that is supposed to work with multiple types still needs to be present for each type. The answer with std::functiion should be the accepted answer... – moritz Apr 04 '20 at 09:06
  • I dont understand how u arrived at the conclusion that this is not a solution, it works well for the ops case in question, see his comment on the question about std::function. It works for diff object types x and y. If you have a better one please post – Samer Tufail Apr 04 '20 at 09:49