मैं एक उपयोगिता फ़ंक्शन की सहायता से एक कैप्चर-फुल लैम्ब्डा फ़ंक्शन को सी-स्टाइल कॉलबैक में पास करना चाहता हूं:

#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 भविष्य में इस समस्या का सामना करने वाले अन्य लोगों के लिए बहुत उपयोगी हो सकता है। यह उत्तर यहां क्योंकि यह कस्टम कॉलबैक हस्ताक्षर का समर्थन करता है (सुनिश्चित नहीं है कि इसका वर्णन कैसे किया जाए)।

मेरा प्रश्न "फ़ंक्शन पॉइंटर के रूप में कैप्चर के साथ लैम्ब्डा" के बारे में प्रश्न से इसका उपयोग करने के बारे में अधिक था।

c++
4
haxpanel 11 सितंबर 2018, 12:08

1 उत्तर

सबसे बढ़िया उत्तर

अपनी कॉलबैक परिभाषाएं देखें:

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 उस अतिरिक्त पैरामीटर के साथ लैम्ब्डा लौटाएगा, क्योंकि आप 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 का रिटर्न प्रकार बदलें।

2
Max Vollmer 11 सितंबर 2018, 12:27