0

I'm doing a MQTT client C++ class using mosquitto:

The class declaration (MQTT.hpp):

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <iostream>
#include <cstring>
#include <chrono>
#include <thread>

#include <mosquitto.h>

class Mqtt
{
    private:
        void on_connect(struct mosquitto *mosq, void *obj, int rc);
        void on_disconnect(struct mosquitto *mosq, void *obj, int rc);
    
    public:
        void loop(void);
};

The class code (MQTT.cpp):

#include "MQTT.hpp"

void Mqtt::on_connect(struct mosquitto *mosq, void *obj, int rc)
{
    std::cout << "on_connect" << std::endl;
}

void Mqtt::on_disconnect(struct mosquitto *mosq, void *obj, int rc)
{
    std::cout << "on_disconnect" << std::endl;
}

void Mqtt::loop()
{
    mosquitto_lib_init();
    struct mosquitto *mosq = mosquitto_new("myid", true, NULL);
    if (!mosq) 
    {
        std::cout << "Cannot initialize broker" << std::endl;
        return;
    }

    mosquitto_connect_callback_set(mosq, std::bind(&Mqtt::on_connect, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
    mosquitto_disconnect_callback_set(mosq, std::bind(&Mqtt::on_disconnect, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));

    mosquitto_loop_start(mosq); 
    mosquitto_connect(mosq, "192.168.0.1", 1883, 60));

    while(true)
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }

    mosquitto_destroy(mosq);
    mosquitto_lib_cleanup();
}

Compile error:

g++ -Wall -g -c Mqtt.cpp
Mqtt.cpp: In member function ‘void Mqtt::loop()’:
Mqtt.cpp:79:51: error: cannot convert ‘std::_Bind_helper<false, void (Mqtt::*)(mosquitto*, void*, int), Mqtt*, const std::_Placeholder<1>&, const std::_Placeholder<2>&, const std::_Placeholder<3>&>::type’ to ‘void (*)(mosquitto*, void*, int)’
   79 |     mosquitto_connect_callback_set(mosq, std::bind(&Mqtt::on_connect, this, _1, _2, _3));
      |                                          ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                                                   |
      |                                                   std::_Bind_helper<false, void (Mqtt::*)(mosquitto*, void*, int), Mqtt*, const std::_Placeholder<1>&, const std::_Placeholder<2>&, const std::_Placeholder<3>&>::type
In file included from Mqtt.hpp:29,
                 from Mqtt.cpp:22:
/usr/include/mosquitto.h:1903:83: note:   initializing argument 2 of ‘void mosquitto_connect_callback_set(mosquitto*, void (*)(mosquitto*, void*, int))’
 1903 | squitto_connect_callback_set(struct mosquitto *mosq, void (*on_connect)(struct mosquitto *, void *, int));
      |                                                      ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Mqtt.cpp:80:54: error: cannot convert ‘std::_Bind_helper<false, void (Mqtt::*)(mosquitto*, void*, int), Mqtt*, const std::_Placeholder<1>&, const std::_Placeholder<2>&, const std::_Placeholder<3>&>::type’ to ‘void (*)(mosquitto*, void*, int)’
   80 |     mosquitto_disconnect_callback_set(mosq, std::bind(&Mqtt::on_disconnect, this, _1, _2, _3));
      |                                             ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      |                                                      |
      |                                                      std::_Bind_helper<false, void (Mqtt::*)(mosquitto*, void*, int), Mqtt*, const std::_Placeholder<1>&, const std::_Placeholder<2>&, const std::_Placeholder<3>&>::type
In file included from Mqtt.hpp:29,
                 from Mqtt.cpp:22:
/usr/include/mosquitto.h:1973:86: note:   initializing argument 2 of ‘void mosquitto_disconnect_callback_set(mosquitto*, void (*)(mosquitto*, void*, int))’
 1973 | itto_disconnect_callback_set(struct mosquitto *mosq, void (*on_disconnect)(struct mosquitto *, void *, int));
      |                                                      ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

make: *** [makefile:19: Mqtt.o] Error 1

Why is it complaining for the arguments match? I don't want to use static member functions, so is there really a way to solve it using std::bind? Am I missing something?

Mendes
  • 17,489
  • 35
  • 150
  • 263

2 Answers2

2

mosquitto_connect_callback_set accepts a pointer to a function. The "thing" that std::bind returns is not convertible to that.

Instead, you can use lambda that does not capture anything, and uses the passed parameter of type void* - converts it to Mqtt* and calls its member function:

mosquitto *mosq = mosquitto_new("myid", true, this);  // <--- note that I changed `NULL` to `this`
// .....
mosquitto_connect_callback_set(mosq, [](struct mosquitto * m, void * pobj, int n){
    Mqtt* obj = (Mqtt*)pobj; // or use static_cast
    obj->on_connect(m, n); // don't need to pass `pobj` here, because `this` is the obj.
});
smitsyn
  • 578
  • 3
  • 6
1

mosquitto is a C-library, and mosquitto_connect_callback_set() expects a pointer to a function with signature void (*)(struct mosquitto *, void *, int), so you have to play by its rules and provide a static function, not the result of std::bind().

There is a mosquittopp binding for C++, where you might be able to work with std::bind() or lambdas.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
stefaanv
  • 14,072
  • 2
  • 31
  • 53