2

I am trying to set a delegate for a function and have the 2 following classes to achieve that.
On the bottom is the error I'm getting. How do I handle it?

Class A

typedef void (*SocketEventString) (String);

class SocketIO 
{
    public:
        SocketIO();
        void onMessage(SocketEventString _cb);


    private:
        SocketEventString _onMessage;

};

Class B

class BoardManager 
    {
        public:
            BoardManager();
            void handleAction(String action);
            SocketIO io;
    };

//Constructor
BoardManager::BoardManager() {

    io.onMessage(  std::bind( &BoardManager::handleAction, this, std::placeholders::_1 ) );
}

ERROR

sketch/BoardManager.cpp: In member function 'void BoardManager::initializeSocketIO()':
BoardManager.cpp:68: error: no matching function for call to 'SocketIO::onMessage(std::_Bind_helper<false, void (BoardManager::*)(String), BoardManager* const, const std::_Placeholder<1>&>::type)'
     io.onMessage(  std::bind( &BoardManager::handleAction, this, std::placeholders::_1 ) );
                                                                                          ^
sketch/BoardManager.cpp:68:90: note: candidate is:
In file included from sketch/BoardManager.h:10:0,
                 from sketch/BoardManager.cpp:8:
sketch/SocketIO.h:25:18: note: void SocketIO::onMessage(SocketEventString)
             void onMessage(SocketEventString _cb);
Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93
dwaksman
  • 119
  • 2
  • 8

2 Answers2

7

The std::bind function return an object that is not compatible or convertible to a pointer to a non-member function.

Instead use std::function:

using SocketEventString = std::function<void(String)>;

With the definition

typedef void (*SocketEventString) (String);

you say that SocketEventString is a pointer to a non-member function (i.e. a function not a member in a class or struct) that takes one argument of type String and returns no value.

The std::bind function returns an object of an unknown class. That object is not the same a the pointer-type you define SocketEventString to be.

The two types (SocketEventString and the object returned by std::bind) are not compatible. You can not convert from one of the types to the other.

The compiler tell you this, because it tries to find a function SocketIO::onMessage which takes the type of the object returned by std::bind and don't find any such overload.

Instead of the SocketEventString type you have defined, you need to use type that is compatible with the object returned by std::bind. That's what I have shown above in my answer, defined SocketEventString to be a different type, a type that is compatible with the type returned by std::bind.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • My assumption was that `SocketID` is a wrapper around some C functions, which would mean that `SocketEventString` would have to be callable from C. That's not stated in the question. – Pete Becker Jan 21 '19 at 17:59
  • I think this has gotten over my head im having trouble following the answers. Some programmer dude thanks for your kind answer. But i still cant get my head around the problem. Do you mind elaborating a bit more please? @PeteBecker, what you say is probably my lack of grasp on the language. Not necessarily a wrapper around C functions. Thanks! – dwaksman Jan 21 '19 at 20:49
  • @dwaksman — I was guessing at what your class does, based only on the name of the class and the member function. Sounds like I’m wrong, so never mind. – Pete Becker Jan 21 '19 at 23:30
  • @dwaksman Added some more more explanation. If that's enough [get a few good books](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list/388282#388282) to learn more about types and the C++ type-system. – Some programmer dude Jan 22 '19 at 05:07
  • @Someprogrammerdude you are the real hero! Thanks so much...im putting the books in my cart now! :) – dwaksman Jan 22 '19 at 12:42
1

Firstly, you can't use a C function pointer for a C++ function binding like that. Essentially, when you use bind it captures some variables to be used in the function call (such as this), so you need to use std::function which handles capturing variables if you want to bind a member function (because member functions at the very least need the this pointer captured). Also, in my opinion, std::bind is fairly ugly, and I recommend getting familiar the new C++ lambdas.

BoardManager::BoardManager() {
    io.onMessage( [&]( String action ) {
        handleAction( action );
    });
}
mukunda
  • 2,908
  • 15
  • 21
  • Im sorry if this sounds trivial, but i tested your solution and still get a similar problem error: no matching function for call to 'SocketIO::onMessage(BoardManager::initializeSocketIO()::__lambda0)'. Anyhow I will surely take your advice and dig into C++ lambdas. Thanks! – dwaksman Jan 21 '19 at 20:02