我可以从C调用std :: function吗?

Stu*_*t K 20 c c++ c++11

我有一些返回的C++代码std::function.我想从一些C代码中调用它.这可能吗?作为一个例子,我有以下代码:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

clang++ -std=c++11 test.cpp它导致以下警告:

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

我明白为什么会这样,但想知道是否有一种模式可以实现这一目标?

R S*_*ahu 15

C/C++之间最便携的接口方法是使用指针在语言之间传递数据,并使用非成员函数进行函数调用.

.h文件:

#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
Run Code Online (Sandbox Code Playgroud)

在.cpp文件中实现它们:

#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;
}
Run Code Online (Sandbox Code Playgroud)


zne*_*eak 8

无法std::function从C 调用,因为C不支持所需的语言功能.C没有模板,访问修饰符,可调用对象,虚拟方法或其他任何std::function可以在引擎盖下使用的东西.您需要提出C可以理解的策略.

一种这样的策略是复制/移动std::function到堆并将其作为不透明指针返回.然后,您将通过C++接口提供另一个函数,该函数接受该不透明指针并调用它包含的函数.

// 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);
    }
};
Run Code Online (Sandbox Code Playgroud)

当然,这会带来内存管理的影响.


Ray*_*mel 5

extern "C"您需要至少将 typedef 放入块内(以使其编译为 C++)。不过,我不确定这在 C 中是否有效。在 C 中可行的就是使用普通函数指针,例如

extern "C" {
using AdderFunction = int(int);
// old-style: typedef int(*AdderFunction)(int);
}
Run Code Online (Sandbox Code Playgroud)

编辑:如果您使用为您提供std::function对象的 API,则可以使用该std::function::target()方法来获取它引用的(可 C 调用的)原始函数指针。

using AdderFunction = std::function<int(int)>;
extern "C" {
using CAdderFunction = int(int);
CAdderFunction makeCAdder(int amount)
{
        return makeAdder(amount).target<CAdderFunction>();
}
}
Run Code Online (Sandbox Code Playgroud)