简体   繁体   English

C ++ Lambda-错误:没有匹配的函数可调用

[英]C++ Lambda - error: no matching function for call to

I am trying to pass a lambda as parameter to a function but once I attempt to access a variable inside the lambda which was declared outside, the build fails: error: no matching function for call to 'AWS::subscribe(char [128], mainTask(void*)::<lambda(AWS_IoT_Client*, char*, uint16_t, IoT_Publish_Message_Params*, void*)>)' 我试图将lambda作为参数传递给函数,但是一旦我尝试访问在外部声明的lambda内部的变量,构建就会失败: error: no matching function for call to 'AWS::subscribe(char [128], mainTask(void*)::<lambda(AWS_IoT_Client*, char*, uint16_t, IoT_Publish_Message_Params*, void*)>)'

I was thinking that the [&] would take care of capturing variables. 我当时以为[&]将负责捕获变量。 I also tried [=] as well as [someVar] , [&someVar] . 我也尝试过[=]以及[someVar][&someVar]

I'm using C++11. 我正在使用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);
  }
);

From the AWS library: 从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);

}

The issue is that the AWS::subscribe function expects a function pointer, not a lambda. 问题在于AWS::subscribe函数需要函数指针,而不是lambda。 Capture-less lambdas can be converted to function pointers, but lambdas with captures (ie state) cannot. 无需捕获的lambda可以转换为函数指针,但是具有捕获(即状态)的lambda不能。

You can see the "conventional" solution to this already in the signature: There is a void* parameter that you should pack all your callback-specific data into. 您可以在签名中看到针对此问题的“常规”解决方案:这里有一个void*参数,您应该将所有特定于回调的数据打包到其中。 Presumably this is the last argument of aws_iot_mqtt_subscribe that you currently set to NULL (prefer using nullptr btw). 大概这是aws_iot_mqtt_subscribe的最后一个参数,您当前将其设置为NULL (最好使用nullptr btw)。

This is uglier than using lambdas, but it's basically the only option for C-compatible library interfaces: 这比使用lambda更为丑陋,但它基本上是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);
void AWS::subscribe(const char *topic,
                    pApplicationHandler_t iot_subscribe_callback_handler,
                    void* ptr) {
  m_error =
      ::aws_iot_mqtt_subscribe(&m_client, topic, (uint16_t)std::strlen(topic),
                              QOS1, iot_subscribe_callback_handler, ptr);

}

then a little utility type: 然后是一个实用程序类型:

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)}; }
}

now we can do: 现在我们可以做:

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()
);

Live example . 现场例子


As I have learned you can modify AWS class, I'd do this: 据了解,您可以修改AWS类,我可以这样做:

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()
    );
}

where subscribe now takes a lambda with signature void(AWS_IoT_Client*, char*, uint16_t, IoT_Publish_Message_Params*) . 现在, subscribe接受带有签名void(AWS_IoT_Client*, char*, uint16_t, IoT_Publish_Message_Params*)

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

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