我有这样的层:C#主应用程序 - 用于C ++库的CLI / C ++包装器 - C ++库。
由于C#-C ++互操作性的限制,编写了CLI中间层。我也使用它来从C#的角度抛光一些粗糙的边缘 - 换句话说,中间层允许隐藏C / C ++类型(如char*
)并进行所有必要的转换。
我未能做的一次转换是传递回调。我尝试在Pass a c++ lambda to old c function pointer中执行此操作,但我无法将lambda作为回调传递。
C ++回调定义:
typedef void (*CppOnEngineCloseCallback)
(void * customParam, const wchar_t * errorMessage);
我知道customParam
未被使用,所以我为中间层定义了这样的回调(CLI / C ++):
typedef void (*CLIOnEngineCloseCallback)
( String ^ errorMessage);
在包装器中我创建了这样的lambda:
// lambda signature should resemble CppOnEngineCloseCallback
auto lambda = [&] (void * customParam, const wchar_t * errorMessage) {
cli_callback(Marshal::PtrToStringUni( IntPtr(static_cast<void*>(
const_cast<wchar_t*>(errorMessage)))));
};
我担心的是,cli_callback
是否会在CLI环境中正确保存(这是我的第一个项目) - 毕竟,我在时间A中传递它,并在时间B中使用它。
编译器更加关注,因为当我尝试使用lambda时:
InitEngine( // C++ function that requires callback
&lambda);
它表示无法将lambda
转换为CppOnEngineCloseCallback
。
首先它是否可行?怎么样?
答案 0 :(得分:0)
您正在使用auto
,因此您隐藏了实际类型,并使自己更难管理C ++强类型类型安全。
lambda函数可能不是正确的类型,或者至少不是你期望的类型。
CppOnEngineCloseCallback
可能是函数指针类型(或std :: funciton类型)
因此,为了帮助自己,请尝试将lambda
的类型更改为预期类型,并查看编译器所说的内容。
CppOnEngineCloseCallback lambda = [&] (void * customParam, const wchar_t * errorMessage) {
cli_callback(Marshal::PtrToStringUni( IntPtr(static_cast<void*>(
const_cast<wchar_t*>(errorMessage)))));
};
InitEngine()
方法需要CppOnEngineCloseCallback
,因此您必须确保获得它。
除此之外,您只能将带有空括号[]
的lambda指定给函数指针。在您的情况下,您没有使用本地范围内的任何内容,因此您实际上并不需要[&]
。
Lambda functions : operator ret(*)(params)()
此用户定义的转换函数仅在捕获时定义 lambda表达式的列表为空。
如果你想使用这种lambda表达式,你将不得不使用std :: function而不是函数指针:
typedef std::function<void(void *, const wchar_t *)> CppOnEngineCloseCallback;
答案 1 :(得分:0)
通常,无法将lambda转换为函数指针。 如您所知,lambda是编译器生成的类的对象,其行为仅类似于函数。
对于您的实际问题:您提到未使用customParam
。
典型的模式是customParam
由库的调用者提供,并在回调函数中用于标识一些处理回调的对象。在回调内部,然后映射到您实际要调用的函数:
void MyNativeCallback(void * customParam, const wchar_t * errorMessage)
{
static_cast<MyClass*>(customParam)->Callback(errorMessage);
}
因此,您可以将指向lambda的指针作为customParam传递给该库,并提供上述的辅助函数作为回调。无论如何,正确获得指针类型将不是一件容易的事。我宁愿选择一个小助手类。