1

I have a C language function to be called:

f_api(void(*callback)(int))

and I have a static class method for the callback:

struct A {
    static void CallBack(int i) {
        A::count = i;
    }
    static count = 0;
};

I can call the function like this:

f_api(&A::CallBack)

However, I have to change the callback to non-static now, because I have to create multiple A objects.

But I cannot change the definition of f_api().

I tried using a lambda:

f_api([this](int i)->void{this->count = i;})`

But this failed, because I cannot convert a lambda with capture into a simple function pointer.

std::bind() also cannot do the work, because of the f_api() definition.

What can I do for this? How can I get a function pointer from a lambda expression? Is there any method to sidestep?

alinsoar
  • 15,386
  • 4
  • 57
  • 74
Liu Weibo
  • 434
  • 5
  • 16
  • You already ruled out the lambda as a solution, so why are you asking about it again? In any case, does the API allow you to pass a user-defined value to the callback? If so, then use that to pass your `this` pointer around. Otherwise, you are SOL without resorting to using a low-level thunk. – Remy Lebeau Jul 28 '17 at 03:34
  • There's nothing you can do. There are no standard tools for forming regular function pointer from member function pointer. If you can't change the callback API, you will have no choice but to route the callbacks through a regular function somehow. – AnT stands with Russia Jul 28 '17 at 03:37
  • @SilvioMayolo It's a little bit difference.. I post a solution that might help others, though it comes no use to me. – Liu Weibo Jul 28 '17 at 05:24
  • If you really want any way at all to transform lambdas (especially closures that capture data) into raw function pointers, I wrote a small library to do that. Beware that this isn't production quality code; it's just a little experiment of mine to see if your problem is solvable at all. Also beware that my implementation is for Linux and OS X only, but the general idea is there if you want something for Windows. https://github.com/MonaTheMonad/c2fp – Mona the Monad Dec 10 '17 at 21:17

2 Answers2

4

If you cannot change the C API then I don't think you can do much about this situation. Because C functions require all the information they require to be passed in as function parameters.

You can convert lambdas to function pointers with the following

void (*ptr) () = []() {}

Lambdas without any capture can be implicitly converted to function pointers. But lambdas which capture values cannot be converted to function pointers since they have extra state (in the form of member variables).

The usual way to solve this problem in C is with void* parameters. Take a look at the pthread_create function. The thread start function accepts a function with a void* parameter which points to a "context". This context in your situation can be something like the instance you are calling the method on.

But if you cannot change the C API, then I am afraid you cannot do much regarding function pointers. The only thing you can do is to make the variables global and then use those to call those methods in the function pointer.

Curious
  • 20,870
  • 8
  • 61
  • 146
0

Here is what I am thinking: Perhaps I can't do it by getting a function pointer from a lambda. But I do some other ticks to get multi-As to sidestep this problem ...

template<unsigned int ClassCount>
struct A {
    static void CallBack(int i) {
        A::count = i;
    }
    static int count;
};

template<unsigned int ClassCount>
int A<ClassCount>::count = 0;

so I can:

f_api(&A<0>::CallBack);
std::cout << A<0>::count << std::endl;
f_api(&A<1>::CallBack);
std::cout << A<1>::count << std::endl; // A<0>::count is different from A<1>::count

this would be a potential solution in some cases, sadly however, not in mines.

Liu Weibo
  • 434
  • 5
  • 16