C++ C++;Lambda-错误:没有用于调用的匹配函数
我正在尝试将lambda作为参数传递给函数,但一旦我尝试访问lambda中在外部声明的变量,构建就会失败:C++ C++;Lambda-错误:没有用于调用的匹配函数,c++,c++11,lambda,closures,C++,C++11,Lambda,Closures,我正在尝试将lambda作为参数传递给函数,但一旦我尝试访问lambda中在外部声明的变量,构建就会失败:错误:没有匹配的函数用于调用“AWS::subscribe(char[128],mainTask(void*):” 我认为[&]将负责捕获变量。我还尝试了[=]以及[someVar],[&someVar] 我正在使用C++11 char someVar[128]; aws->subscribe( topic, [&] (AWS_IoT_Client *pClient,
错误:没有匹配的函数用于调用“AWS::subscribe(char[128],mainTask(void*):”
我认为[&]
将负责捕获变量。我还尝试了[=]
以及[someVar]
,[&someVar]
我正在使用C++11
char someVar[128];
aws->subscribe(
topic,
[&] (AWS_IoT_Client *pClient, char *topicName, uint16_t topicNameLen, IoT_Publish_Message_Params *params, void *pData) {
char *text = (char *)params->payload;
sprintf(someVar, "%s", text);
}
);
从AWS库:
void AWS::subscribe(const char *topic,
pApplicationHandler_t iot_subscribe_callback_handler) {
m_error =
::aws_iot_mqtt_subscribe(&m_client, topic, (uint16_t)std::strlen(topic),
QOS1, iot_subscribe_callback_handler, NULL);
}
问题在于
AWS::subscribe
函数需要函数指针,而不是lambda。无捕获的lambda可以转换为函数指针,但具有捕获(即状态)的lambda不能
您可以在签名中看到解决此问题的“常规”解决方案:有一个void*
参数,您应该将所有回调特定数据打包到该参数中。这大概是aws\u iot\u mqtt\u subscribe
的最后一个参数,您当前将其设置为NULL
(首选使用nullptr
btw)
这比使用lambdas更丑陋,但它基本上是C兼容库接口的唯一选项:
// Your callback (could also be a capture-less lambda):
void callbackFunc(/* etc. */, void *pData)
{
std::string* someVarPtr = static_cast<std::string*>(pData);
char *text = (char *)params->payload;
sprintf(*someVarPtr, "%s", text);
}
// To subscribe:
std::string someVar;
void* callbackData = &someVar; // Or a struct containing e.g. pointers to all your data.
aws_iot_mqtt_subscribe(/* etc. */, callbackFunc, callbackData);
//您的回调(也可以是无捕获lambda):
void callbackFunc(/*etc.*/,void*pData)
{
std::string*someVarPtr=static_cast(pData);
字符*文本=(字符*)参数->有效载荷;
sprintf(*someVarPtr,“%s”,文本);
}
//认购:
std::字符串someVar;
void*callbackData=&someVar;//或包含指向所有数据的指针的结构。
aws_iot_mqtt_subscribe(/*etc.*/,callbackFunc,callbackData);
然后是一个小实用程序类型:
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)}; }
}
其中,
subscribe
现在接受一个带有签名的lambdavoid(AWS\u IoT\u Client*、char*、uint16\u t、IoT\u Publish\u Message\u Params*)
一个lambda函数。我明白了,谢谢。你能推荐一种解决这个问题的方法吗?我想最好的办法是将AWS::subscribe
的签名改为期望一个lambda,但不知何故它会将其转换为引擎盖下的函数指针。因此,aws\u iot\u mqtt\u subscribe
会“吃掉”它。注意,AWS库不是官方的库,它只是一个片段,所以它不会改变它。@ Jejo并不是C++意义上的“转换”。当然,您可以通过将lambda对象本身设置为void*
并使用一个包装函数来“转换”它。更不用说lambda本身的生存期缺陷(在调用发生之前,它必须保持在作用域内…。@MaxLanghof您能告诉我lambda作为数据而不是字符串时会是什么样子吗?谢谢这里唯一的问题我在尝试编译时收到各种错误消息。:-/utils.cpp:7:7:错误:“return”返回[](Args…Args,void*fptr)->void{
和utils.cpp:12:29:错误:“f”未在此范围内声明return std::addressof(f)
还有一些。请检查一下好吗?Thanks@haxpanel修复了3个拼写错误。最糟糕的是返回函数指针的函数,这不是我通常直接做的事情。添加了一个最小的假的AWS测试工具的实例。我仍然得到错误:没有匹配的函数用于调用,但这次甚至使用无捕获的lambda。我按照您的示例做了所有事情,我不知道会出什么问题。@haxpanel如果错误在get\u回调
中,lambda的签名(以及传递给get\u回调
的参数)不应该有“trailingvoid*
”字样;由get\u callback
添加。void*
用于存储指向lambda的指针。删除task.get\u pvoid()
我从哪里调用subscribe
解决了这个问题!我遗漏了subscribe
的签名不同。我不太确定引擎盖下发生了什么,传递函数的地址有用吗?
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)}; }
}
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);
}
);
aws->subscribe(
topic,
task.get_callback<AWS_IoT_Client*, char*, uint16_t, IoT_Publish_Message_Params*>(),
task.get_pvoid()
);
template<class Handler>
void AWS::subscribe(const char *topic,
Handler iot_subscribe_callback_handler) {
auto task = utils::c_style_callback(iot_subscribe_callback_handler);
m_error =
::aws_iot_mqtt_subscribe(
&m_client,
topic,
(uint16_t)std::strlen(topic),
QOS1,
task.get_callback<AWS_IoT_Client*, char*, uint16_t, IoT_Publish_Message_Params*>(),
task.get_pvoid()
);
}