Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/125.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;Lambda-错误:没有用于调用的匹配函数_C++_C++11_Lambda_Closures - Fatal编程技术网

C++ C++;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,

我正在尝试将lambda作为参数传递给函数,但一旦我尝试访问lambda中在外部声明的变量,构建就会失败:
错误:没有匹配的函数用于调用“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
现在接受一个带有签名的lambda
void(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回调
的参数)不应该有“trailing
void*
”字样;由
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()
    );
}