0

I am new to C++ and I am having trouble with pointer functions to member functions. I am programming with PlatformIO on an ESP8266.

UdpTask.h

class UdpTask : public Task {
  public:
    void setup();
    void loop();
    UdpTask(String (*handleGson)(String));
  private:
    char replyPacket[];
    char incomingPacket[UDP_TX_PACKET_MAX_SIZE];
    unsigned int localUdpPort;
    WiFiUDP Udp;
    String (*handleGson)(String);
};

UdpTask.cpp

UdpTask::UdpTask(String(*handleGson)(String)) {
  this->handleGson = handleGson; 
}

GsonHandler.h

class GsonHandler {
  public:
    String handleGson(String gson);
}; 

GsonHandler.cpp

String GsonHandler::handleGson(String gson) {
  return ":)";
}

main.cpp

GsonHandler gsonHandler;
UdpTask udpTask(&gsonHandler.handleGson);

Error:

src\main.cpp:16:30: error: ISO C++ forbids taking the address of a bound member function to form a pointer to member function.  Say '&GsonHandler::handleGson' [-fpermissive]
 UdpTask udpTask(&gsonHandler.handleGson);
                              ^
src\main.cpp:16:40: error: no matching function for call to 'UdpTask::UdpTask(String (GsonHandler::*)(String))'
 UdpTask udpTask(&gsonHandler.handleGson);

Note: I've tried the suggestions in the error message, but I can't find a way to get it to work..., furthermore, I know that in this simple example it can be solved much easier with for example just passing the whole object but I need this kind of pointers again where this way is easier.

Thanks in advance.

Maxdola
  • 1,562
  • 2
  • 10
  • 29
  • Can `GsonHandler::handleGson` be `static`? You cannot use a pointer to a non-static member function as if it was a pointer to a normal function. These are fundamentally incompatible. If `static` is not an object, you should probably save a `std::function` instead. – walnut Feb 03 '20 at 00:34
  • are you trying to use *closures* ? (that is, an object along with a member function of that object). A pointer-to-member is not associated with any specific object – M.M Feb 03 '20 at 00:55

1 Answers1

1

As it was pointed out already in the comments - the argument that UdpTask(String (*handleGson)(String)); constructor expects is not a pointer to a member function. Rather it is a pointer to a free function. A pointer to a member function would be of the form:

String (GsonHandler::*)(String) 

Note that pointer to a member need to know a member of what type it is.

As to your original problem - there are a number of ways to solve it (as always the case with C++).

Most straightforward is to use std::function<String(String)> to store a functor. That is any object that can be called. So something like:

class UdpTask : public Task {
  public:
    UdpTask(std::function<String(String)> f);
  private:
...
std::function<String(String)> handler;
};

In the implementation, you just call it as: handler(args);

In case you can not use std function - other solutions can be explored.

Simplest would be to store a pointer to a handler in you UdpTask and call its method directly:

class UdpTask : public Task {
  public:
    UdpTask(GsonHandler* handler);
  private:
...
GsonHandler* handler;
};

In the implementation, you just call it as: handler->handleGson(args);

Now, I do recognise that there might be arcitual concerns about tight coupling between UdpTask and what is eccentially a UDP data handler. So you may consideg making generic interface for DataHandler, storing pointer to it and making GsonHandler an implementation of DataHandler:

struct DataHandler {
virtual ~DataHandler() = default;
virtual String handleData(String data) = 0;
}; 

struct GsonHandler: public DataHandler {
 String handleData(String data) override;
...
};
...


class UdpTask : public Task {
  public:
    UdpTask(DataHandler* handler);
  private:
...
DataHandler* handler;
};

AbbysSoul
  • 393
  • 1
  • 7
  • This is exactly what I was searching for thanks a lot. – Maxdola Feb 03 '20 at 00:58
  • Yeah - this is a straightforward way to do it. It may not work for a platform with limited support for c++ stl library. Don't know the details for `ESP8266`. Could you please comment if it std::function<> worked for you? – AbbysSoul Feb 03 '20 at 01:08