如何围绕C风格的回调创建lambda-wrapper?

时间:2014-10-24 07:56:36

标签: c# visual-c++ lambda c++-cli

我有这样的层: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

首先它是否可行?怎么样?

2 个答案:

答案 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传递给该库,并提供上述的辅助函数作为回调。无论如何,正确获得指针类型将不是一件容易的事。我宁愿选择一个小助手类。