0

Say I have a function foo:

void foo(void (*ftn)(int x))
{
  ftn(5);
}

It needs as a parameter a void function that accepts an int as a parameter. Consider

void func1(int x) {}

class X {
public:
  void func2(int x) {}
};

Now foo(&func1) is ok.

But foo(&X::func2) isn't ok because X::func2 isn't static and needs a context object and its function pointer type is different.

I tried foo(std::bind(&X:func2, this)) from inside X but that raises a type mismatch too.

What is the right way of doing this?

batman
  • 5,022
  • 11
  • 52
  • 82
  • Consider changing your function to take a `std::function` as it's argument. That way you can use `std::bind` to transparently use either a free function, static member function, or non-static member function. – Captain Obvlious Nov 01 '14 at 18:32
  • template function foo is most likely the easiest solution to go with. Edit: Yes as mentioned above, even easier may be std::function – Creris Nov 01 '14 at 18:32
  • What if I'm not allowed to change `foo` (part of a library) ? – batman Nov 01 '14 at 18:39
  • 1
    It helps to remember `void (*ftn)(int x)` as *just* an address of a function that takes a single `int`. You cannot call `X::func2` if you just know the method's address. You do need the method's address, but you need more than just that (you need an object instance), so it clearly cannot fit in a single `void (*)(int)` value. There's just no way around that. You *might* use additional global variables (`X *x; void x_func2(int y) { x->func2(y); }`, and set `x` to a sensible value), but it's a solution that doesn't scale. (I know I'm not using terms in the same sense as the C++ standard here.) –  Nov 01 '14 at 18:41
  • 1
    Is that function pointer the **only** argument to `foo`? Show us the real declaration of the library function. – rob mayoff Nov 01 '14 at 18:49
  • @hvd can you write that as an answer. I find the part that the address alone isn't sufficient to be very helpful. – batman Nov 02 '14 at 05:46
  • @robmayoff, yes. Actually it is a C-library. So that is why they haven't cared much about this. :) – batman Nov 02 '14 at 05:47

1 Answers1

2

Based on the comments, if you cannot change the signature of foo to take anything but a raw function pointer... then you'll have to do something like this:

struct XFunc2Wrapper {
    static X* x;

    static void func2(int v) {
        x->func2(v);
    }
};

And then just do foo(&XFunc2Wrapper::func2) once you set XFunc2Wrapper::x to be your X. It doesn't have to be nested in a struct, it can just be some global pointer, but nesting helps establish the intent behind the code better.

But this should definitely be last resort after (as per Captain Obvlious) trying to do foo(std::function<void(int)> ).

Barry
  • 286,269
  • 29
  • 621
  • 977