tags:

views:

782

answers:

9

I'm trying to use a C library in a C++ app and have found my self in the following situation (I know my C, but I'm fairly new to C++). On the C side I have a collection of functions that takes a function pointer as their argument. On the C++ side I have objects with a functor which has the same signature as the function pointer needed by the C function. Is there any way to use the C++ functor as a function pointer to pass to the C function?

+2  A: 

I don't think you can: operator() in a function object is really a member function, and C doesn't know anything about those.

What you should be able to use are free C++ functions, or static functions of classes.

UncleBens
A: 

It depends if this is a static or instance method, if it is static then you can pass through the function as className::functionName, if it is an instance method it is fair more complicated, because you obviously need to tie to a certain instance but can't do it in the same way as you would with delegates in C# etc.

The best way I've found of doing this is to create a holding class which is instantiated with the instance of the object as well as the function pointer, the holding class can then invoke the function directly.

Tim
+1  A: 

No, of course. The signature of your C function take an argument as function.

void f(void (*func)())
{
  func(); // Only void f1(), void F2(), ....
}

All tricks with functors are used by template fucntions:

template<class Func>
void f (Func func)
{
    func(); // Any functor
}
Alexey Malistov
A: 

I would say no, because a C++ functor has an overloaded operator () which is a member function, and would thus require a member function pointer. This is a totally different data type than a normal C function pointer, since it cannot be invoked without an instance of the class. You'd need to pass a normal function or a static member function to the C library. Since an overloaded () operator can't be static, you can't do it. You'd need to pass the C-library a normal, non-member function or static member function, from which you can then invoke the C++ functor.

Charles Salvia
A: 

Hm, maybe you could write a free template function that wraps around your function-objects. If they all have the same signature, this should work. Like this (not tested):

template<class T>
int function_wrapper(int a, int b) {
    T function_object_instance;

    return funcion_object_instance( a, b );
}

This would do for all function that take two ints and return an int.

Space_C0wb0y
+2  A: 

I found this "gem" using google. Apparently possible but I sure wouldn't recommend it. Direct link to example source code.

Andreas Brinck
Please don't use this. It should be trivial to wrap your functor in a regular C function and doesn't require an ugly hack.
Ron Warholic
+2  A: 

A C callback function written in C++ must be declared as an extern "C" function - so using a functor directly is out. You'll need to write some sort of wrapper function to use as that callback and have that wrapper call the functor. Of course, the callback protocol will need to have some way of passing context to the function so it can get to the functor, or the task becomes quite tricky. Most callback schemes have a way to pass context, but I've worked with some brain-dead ones that don't.

See this answer for some more details (and look in the comments for anecdotal evidence that the callback must be extern "C" and not just a static member function):

Michael Burr
A: 

Many C APIs that take function pointer callbacks have a void* parameter for user state. If you've got one of those, you're in luck - you can use an exterm C function that treats the user data as some sort of reference or key to lookup the functor, then execute it.

Otherwise, no.

Joe Gauterin
+6  A: 

You cannot directly pass a pointer to C++ functor object as a function pointer to C code (or even to C++ code).

Additionally, to portably pass a callback to C code it needs to be at least declared as extern "C" non-member function. At least, because some APIs require specific function call conventions and thus additional declaration modifiers.

In many environments C and C++ have the same calling conventions and differ only in name mangling, so any global function or static member will work. But you still need to wrap call to operator() in normal function.

  • If your functor has no state (it is an object just to satisfy some formal requirements etc):

    class MyFunctor {
      // no state
     public:
      MyFunctor();
      int operator(SomeType &param) const;
    }
    

    you can write normal extern "C" function which creates functor and executes its operator().

    extern "C" int MyFunctorInC(SomeType *param)
    {
      static MyFunctor my_functor;
      return my_functor(*param);
    }
    
  • If your functor has state, eg:

    class MyFunctor {
      // Some fields here;
     public:
      MyFunctor(/* some parameters to set state */);
      int operator(SomeType &param) const;
      // + some methods to retrieve result.
    }
    

    and C callback function takes some kind of user state parameter (usually void *):

    void MyAlgorithmInC(SomeType *arr,
                        int (*fun)(SomeType *, void *),
                        void *user_state);
    

    you can write normal extern "C" function which casts its state parameter to your functor object:

    extern "C" int MyFunctorInC(SomeType *param, void *user_state)
    {
      MyFunctor *my_functor = (MyFunctor *)user_state;
      return (*my_functor)(*param);
    }
    

    and use it like this:

    MyFunctor my_functor(/* setup parameters */);
    MyAlgorithmInC(input_data, MyFunctorInC, &my_functor);
    
  • Otherwise the only normal way to do it (normal as in "without generating machine code at runtime" etc.) is to use some static (global) or thread local storage to pass functor to extern "C" function. This limits what you can do with your code and is ugly but will work.

Tomek Szpakowicz
+1, a detailed write-up of possible cases.
Pavel Minaev
+1, although the callback signature is definitely not C :)
quinmars
oops, nvm, somehow I mixed the declarations and thought you are using references in C here.
quinmars
@quinmars: I was wondering how soon someone gets confused by this. You've got to love C++ references...
Tomek Szpakowicz
Good write-up. Would this still work if the free wrapper function was a template function as I have described in my answer below?
Space_C0wb0y