Search code examples
c++staticboost-threadpointer-to-member

How to use member functions array in a static function?


I have a class, called Channel_thread. As you can guess, one of its function is threaded, and in this function I would like to call another member function, depending on situations. That's why I used an array of member functions.


Here is how the code looks like :

Channel_thread.cpp :

#include <boost/bind.hpp>
#include "../include/Channel_thread.h"


Channel_thread::Channel_thread(Event_queue<std::deque<char>> *_serverQueue, Event_queue<std::deque<char>> *_messageQueue)
{
    serverQueue = _serverQueue;
    messageQueue = _messageQueue;

}

void Channel_thread::startThread()
{
    isRunning = true;

    t = new boost::thread(boost::bind(&Channel_thread::start, this));
}

void Channel_thread::start(void *data)
{
    auto *_this = (Channel_thread *)data;
    Message *messageReceived = NULL;

    while (_this->isRunning)
    {
        std::pair<std::string, std::deque<char>> p(_this->messageQueue->wait_and_pop());
        for (int index = 0; index != 4; index++)
        {
            if (_this->handlersIndexTab[index] == p.first)
            {
                messageReceived = _this->handlersTab[index](p.second);
                break ;
            }
        }
    }
}

Message *Channel_thread::channelSetupHandler(std::deque<char> bytes)
{
//Do stuff
}

Message *Channel_thread::channelStatusHandler(std::deque<char> bytes)
{
//Do stuff
}

Message *Channel_thread::channelCloseHandler(std::deque<char> bytes)
{
//Do stuff
}

Message *Channel_thread::streamSetupHandler(std::deque<char> bytes)
{
//Do stuff
}

Channel_thread.h

#include <boost/thread.hpp>
#include "Event_queue.h"
#include "Channel_setup.h"
#include "Channel_status.h"
#include "Channel_close.h"
#include "Stream_setup.h"

class Channel_thread {

    typedef Message *(Channel_thread::*fn)(std::deque<char>);


public:
    Channel_thread(Event_queue<std::deque<char>> *, Event_queue<std::deque<char>> *);

    static void start(void *);

    void startThread();

    Message *channelSetupHandler(std::deque<char>);
    Message *channelStatusHandler(std::deque<char>);
    Message *channelCloseHandler(std::deque<char>);
    Message *streamSetupHandler(std::deque<char>);

private:
    Event_queue<std::deque<char>> *messageQueue;
    Event_queue<std::deque<char>> *serverQueue;

    bool isRunning;
    boost::thread *t;

    fn handlersTab[4] = {channelSetupHandler, channelStatusHandler, channelCloseHandler, streamSetupHandler};
    std::string handlersIndexTab[4] = {"channel_setup", "channel_status", "channel_close", "stream_setup"};
};

I get this error :

/cygdrive/c/Users/foo/CLionProjects/Server_cpp/src/Channel_thread.cpp: In static member function 'static void Channel_thread::start(void*)':
/cygdrive/c/Users/foo/CLionProjects/Server_cpp/src/Channel_thread.cpp:35:69: error: must use '.*' or '->*' to call pointer-to-member function in '_this->Channel_thread::handlersTab[index] (...)', e.g. '(... ->* _this->Channel_thread::handlersTab[index]) (...)'
                 messageReceived = _this->handlersTab[index](p.second);

As you can see, the way I call a member function in my array seems to be wrong, maybe because of the static context, I don't really know, and so my question is :

How to call member functions stored in an member functions array from a static function?

Thanks in advance.


Solution

  • There are couple of problems with using _this->handlersTab[index](p.second);.

    1. The syntax for using a member function pointer is different than using a member function. A member function pointer needs to be dereferenced before getting called. Give a member function pointer, mfPtr, the syntax to use is (objectPtr->*mfPtr)(...). See the section Pointers to member functions at https://en.cppreference.com/w/cpp/language/pointer for further details.

    2. The second problem is that handlersTab is not a static member variable. To get a pointer to the member function, you have to use _this->handlersTab.

    A one liner to make the function call would be:

    messageReceived = (_this->*(_this->handlersTab[index]))(p.second);
    

    I would suggest simplifying it by using two lines.

    fn handler = _this->handlersTab[index];
    messageReceived = (_this->*handler)(p.second);