简体   繁体   English

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

[英]How to create lambda-wrapper around C-style callback?

I have such layers: C# main application -- CLI/C++ wrapper for C++ library -- C++ library. 我有这样的层:C#主应用程序 - 用于C ++库的CLI / C ++包装器 - C ++库。

CLI middle layer was written because of the limitations of C#-C++ interoperability. 由于C#-C ++互操作性的限制,编写了CLI中间层。 I used it also to polish some rough edges from C# point of view -- in other words, the middle layer allows to hide C/C++ types (like char* ) and do all necessary conversions. 我也使用它来从C#的角度抛光一些粗糙的边缘 - 换句话说,中间层允许隐藏C / C ++类型(如char* )并进行所有必要的转换。

One conversion I fail to make is passing a callback. 我没能做的一次转换是通过回调。 I tried to do it as in Pass a c++ lambda to old c function pointer but I cannot pass a lambda as a callback. 我尝试将它传递给c ++ lambda到旧的c函数指针,但是我不能将lambda作为回调传递。

C++ callback definition: C ++回调定义:

typedef void (*CppOnEngineCloseCallback)
    (void * customParam, const wchar_t * errorMessage);

I know customParam is not used, so I define such callback for middle layer (CLI/C++): 我知道不使用customParam ,所以我为中间层定义了这样的回调(CLI / C ++):

typedef void (*CLIOnEngineCloseCallback)
        ( String ^ errorMessage);

In the wrapper I create such lambda: 在包装器中我创建了这样的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)))));
};

My concern is if cli_callback will be properly kept in CLI environment (this is my first project) -- after all, I pass it in time A, and use it in time B. 我担心的是cli_callback是否会在CLI环境中正确保存(这是我的第一个项目) - 毕竟,我在时间A中传递它,并在时间B中使用它。

Compiler has even stronger concern, because when I try to use the lambda: 编译器更受关注,因为当我尝试使用lambda时:

InitEngine( // C++ function that requires callback
    &lambda);

it says it cannot convert lambda into CppOnEngineCloseCallback . 它说它无法将lambda转换为CppOnEngineCloseCallback

Is it doable in the first place? 它首先是可行的吗? How? 怎么样?

You're using auto , hence you're hiding the actual type, and making it harder on yourself to manage the C++ strongly typed type safety. 你正在使用auto ,因此你隐藏了实际类型,并且让你自己更难管理C ++强类型类型的安全性。

Probably the lambda function isn't the right type, or at least not the type you're expecting. 可能lambda函数不是正确的类型,或者至少不是您期望的类型。

CppOnEngineCloseCallback is probably a function pointer type (or std::funciton type). CppOnEngineCloseCallback可能是函数指针类型(或std :: funciton类型)。
So, to help yourself, try changing the lambda 's type to the expected type, and see what the compiler says. 因此,为了帮助自己,尝试将lambda的类型更改为期望的类型,并查看编译器所说的内容。

CppOnEngineCloseCallback lambda = [&] (void * customParam, const wchar_t * errorMessage) {
    cli_callback(Marshal::PtrToStringUni( IntPtr(static_cast<void*>(
        const_cast<wchar_t*>(errorMessage)))));
};

The InitEngine() method expects a CppOnEngineCloseCallback , so you must make sure it gets it. InitEngine()方法需要一个CppOnEngineCloseCallback ,因此您必须确保它获取它。

Besides that, you can only assign a lambda with empty brackets [] to a function pointer. 除此之外,您只能将带有空括号[]的lambda指定给函数指针。 In your case you're not using anything from the local scope, hence you don't really need [&] . 在你的情况下,你没有使用本地范围内的任何东西,因此你并不需要[&]

Lambda functions : operator ret(*)(params)() Lambda函数:operator ret(*)(params)()

This user-defined conversion function is only defined if the capture list of the lambda-expression is empty. 仅当lambda表达式的捕获列表为空时,才定义此用户定义的转换函数。

If you do want to use this kind of lambda expression, you'll have to use std::function instead of a function pointer: 如果你想使用这种lambda表达式,你将不得不使用std :: function而不是函数指针:

typedef std::function<void(void *, const wchar_t *)> CppOnEngineCloseCallback;

In general, it is not possible, to cast a lambda to a function pointer. 通常,将lambda转换为函数指针是不可能的。 As you know, a lambda is an object of a compiler generated class, that only behaves like a function. 如您所知,lambda是编译器生成的类的对象,其行为类似于函数。

For your actual problem: you mentioned that customParam is not used. 对于您的实际问题:您提到不使用customParam

A typical pattern is, that customParam is provided by the caller of the library and used in the callback function to identify some object handling the callback. 典型的模式是, customParam由库的调用者提供,并在回调函数中用于标识处理回调的某个对象。 Inside the callback, you then map to the function you actually want to call: 在回调中,然后映射到您实际要调用的函数:

void MyNativeCallback(void * customParam, const wchar_t * errorMessage)
{
    static_cast<MyClass*>(customParam)->Callback(errorMessage);
}

So you could pass a pointer to your lambda as customParam to the library, and provide a helper function as above as callback. 因此,您可以将指向lambda的指针作为customParam传递给库,并提供上面的辅助函数作为回调。 Anyways, getting the pointer types correctly will not be a simple task. 无论如何,正确获取指针类型不是一项简单的任务。 I would prefer a small helper class instead. 我宁愿选择一个小帮手类。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM