通过实用程序 fn 将捕获的 lambda 传递给 C 样式回调 - 错误

Passing capture-ful lambda to C-style callback through utility fn - error

本文关键字:样式 回调 错误 lambda fn 实用程序      更新时间:2023-10-16

我想借助实用程序函数将捕获的lambda函数传递给C样式回调:

#include <utility>
#include <iostream>
#include <array>
struct AWS_IoT_Client {};
struct IoT_Publish_Message_Params {
int payload[1024];
};
typedef enum {
SHADOW_ACK_TIMEOUT, SHADOW_ACK_REJECTED, SHADOW_ACK_ACCEPTED
} Shadow_Ack_Status_t;
typedef enum {
SHADOW_GET, SHADOW_UPDATE, SHADOW_DELETE
} ShadowActions_t;
typedef void (*pApplicationHandler_t)(AWS_IoT_Client *pClient, char *pTopicName, uint16_t topicNameLen,
IoT_Publish_Message_Params *pParams, void *pClientData);
typedef void (*fpActionCallback_t)(const char *pThingName, ShadowActions_t action, Shadow_Ack_Status_t status,
const char *pReceivedJsonDocument, void *pContextData);
struct AWS {
inline void subscribe(char*, pApplicationHandler_t, void*)
{
}
inline void get_shadow(fpActionCallback_t, void *)
{
}
};
AWS* aws = new AWS;
namespace utils {
template<class F>
struct c_style_callback_t {
F f;
template<class...Args>
static void(*get_callback())(Args..., void*) {
return [](Args...args, void* fptr)->void {
(*static_cast<F*>(fptr))(std::forward<Args>(args)...);
};
}
void* get_pvoid() {
return std::addressof(f);
}
};
template<class F>
c_style_callback_t< std::decay_t<F> >
c_style_callback( F&& f ) { return {std::forward<F>(f)}; }
}
int main() {
char someVar[1024]={0};
auto task2 = utils::c_style_callback(
[&] (const char *pThingName, ShadowActions_t action, Shadow_Ack_Status_t status,
const char *pReceivedJsonDocument, void *pContextData) {
//sprintf(someVar, "%s", text);
}
);
aws->get_shadow(
task2.get_callback<const char*, ShadowActions_t, Shadow_Ack_Status_t, const char*, void*>(),
task2.get_pvoid()
);
auto task = utils::c_style_callback(
[&] (AWS_IoT_Client *pClient, char *topicName, uint16_t topicNameLen, IoT_Publish_Message_Params *params) {
char *text = (char *)params->payload;
sprintf(someVar, "%s", text);
}
);

但是,我没有收到其他回调的错误:

char topic[] = "some topic";
aws->subscribe(
topic,
task.get_callback<AWS_IoT_Client*, char*, uint16_t, IoT_Publish_Message_Params*>(),
task.get_pvoid()
);
}

错误信息:

error: cannot initialize a parameter of type 'fpActionCallback_t' (aka 'void (*)(const char *, ShadowActions_t, Shadow_Ack_Status_t, const char *, void *)') with an rvalue of type 'void (*)(const char *, ShadowActions_t, Shadow_Ack_Status_t, const char *, void *, void *)': different number of parameters (5 vs 6)
task2.get_callback<const char*, ShadowActions_t, Shadow_Ack_Status_t, const char*, void*>()`

我不明白为什么。

现场示例

更新:

我要强调的是,实用程序函数c_style_callback对于将来遇到此问题的其他人非常有用。这是一个比这里答案中的解决方案更灵活的解决方案,因为这个解决方案支持自定义回调签名(不确定如何描述它(。

我的问题更多的是关于使用它,而不是关于"将捕获作为函数指针的lambda"的问题。

查看您的回调定义:

typedef void (*pApplicationHandler_t)(AWS_IoT_Client *pClient, char *pTopicName, uint16_t topicNameLen, IoT_Publish_Message_Params *pParams, void *pClientData);
typedef void (*fpActionCallback_t)(const char *pThingName, ShadowActions_t action, Shadow_Ack_Status_t status, const char *pReceivedJsonDocument, void *pContextData);

以及每种情况下的回调参数:

task.get_callback<AWS_IoT_Client*, char*, uint16_t, IoT_Publish_Message_Params*>()
task2.get_callback<const char*, ShadowActions_t, Shadow_Ack_Status_t, const char*, void*>()

在第一种情况下,您有一个附加参数void* pClientData,在后一种情况下,即使get_callback将返回带有该附加参数的lambda,您也不会,因为您返回的是return [](Args...args, void* fptr),而不是return [](Args...args)

因此,请将您的第二个类型定义更改为:

typedef void (*fpActionCallback_t)(const char *pThingName, ShadowActions_t action, Shadow_Ack_Status_t status, const char *pReceivedJsonDocument, void *pContextData, void *pClientData);

或更改返回类型get_callback