Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I call a std::function from C?

Tags:

I have some C++ code that returns a std::function. I would like to call this from some C code. Is this possible? As an example I have the following code:

typedef std::function<int(int)> AdderFunction;  AdderFunction makeAdder(int amount) {     return [amount] (int n) {         return n + amount;     }; }  extern "C" {     AdderFunction makeCAdder(int amount) {         return makeAdder(amount);     } } 

with clang++ -std=c++11 test.cpp it results in the following warning:

'makeCAdder' has C-linkage specified, but returns user-defined type 'AdderFunction' (aka 'function<int (int)>') which is incompatible with C 

I understand why this is happening, but wondering if there is a pattern to make it possible?

like image 354
Stuart K Avatar asked Nov 01 '17 20:11

Stuart K


People also ask

What is std :: in C?

std is the namespace and by using :: (after the std) you explicitly using the functions of the namespace std. Now, imagine that you create your own namespace and some of the functions that you have created there have the same name as the functions in std namespace.

How do you call a STD function in C++?

The stored callable object is called the target of std::function . If a std::function contains no target, it is called empty. Invoking the target of an empty std::function results in std::bad_function_call exception being thrown.

Can std :: function be copied?

You can recover the desired behavior by always using thread-local copies of the std::function because they'll each have an isolated copy of the state variables.

Should std :: function be passed by value?

If there is any possibility you are storing a copy of the std::function , pass by value. Otherwise, either way is roughly equivalent: the only downside to by-value is if you are taking the same bulky std::function and having one sub method after another use it. Barring that, a move will be as efficient as a const& .


2 Answers

The most portable method to interface between C/C++ will be to use pointers to pass data between languages and use non-member functions to make function calls.

The .h file:

#ifdef __cplusplus extern "C" { #endif     // Declare the struct.    struct Adder;     // Declare functions to work with the struct.    Adder* makeAdder(int amount);     int invokeAdder(Adder* adder, int n);     void deleteAdder(Adder* adder);  #ifdef __cplusplus } #endif 

Implement them in a .cpp file as:

#include <functional>  typedef std::function<int(int)> AdderFunction; struct Adder {    AdderFunction f; };  AdderFunction makeAdderFunction(int amount) {     return [amount] (int n) {         return n + amount;     }; }  Adder* makeAdder(int amount) {    Adder* adder = new Adder;    adder->f = makeAdderFunction(amount);    return adder; }  int invokeAdder(Adder* adder, int n) {    return adder->f(n); }  void deleteAdder(Adder* adder) {    delete adder; } 
like image 153
R Sahu Avatar answered Sep 27 '22 19:09

R Sahu


It's not possible to call a std::function from C, because C doesn't support the language features that are required. C doesn't have templates, access modifiers, callable objects, virtual methods, or anything else that std::function could use under the hood. You need to come up with a strategy that C can understand.

One such strategy is to copy/move your std::function to the heap and return it as an opaque pointer. Then, you would provide another function through your C++ interface that takes that opaque pointer and calls the function that it contains.

// C side struct function_opaque; int call_opaque(struct function_opaque*, int param);  // C++ side extern "C" {     struct function_opaque {         std::function<int(int)> f;     };      int call_opaque(function_opaque* func, int param) {         return func->f(param);     } }; 

Of course, this comes with memory management implications.

like image 20
zneak Avatar answered Sep 27 '22 19:09

zneak