如何在静态函数中使用成员函数数组?
How to use member functions array in a static function?
我有一个 class,叫做 Channel_thread
。你可以猜到,它的一个函数是线程化的,在这个函数中我想调用另一个成员函数,视情况而定。这就是我使用成员函数数组的原因。
代码如下所示:
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"};
};
我收到此错误:
/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);
如您所见,我在数组中调用成员函数的方式似乎是错误的,可能是因为 static
上下文,我真的不知道,所以我的问题是:
如何从静态函数调用存储在成员函数数组中的成员函数?
提前致谢。
使用 _this->handlersTab[index](p.second);
有几个问题。
使用成员函数指针的语法与使用成员函数的语法不同。成员函数指针在调用之前需要取消引用。给一个成员函数指针,mfPtr
,使用的语法是(objectPtr->*mfPtr)(...)
。有关详细信息,请参阅 https://en.cppreference.com/w/cpp/language/pointer 中的 成员函数指针 部分。
第二个问题是handlersTab
不是static
的成员变量。要获得指向成员函数的指针,您必须使用 _this->handlersTab
.
进行函数调用的一行是:
messageReceived = (_this->*(_this->handlersTab[index]))(p.second);
我建议使用两行来简化它。
fn handler = _this->handlersTab[index];
messageReceived = (_this->*handler)(p.second);
如果您使用的是 c++17,最简单的解决方案是在函数 header.
中使用 std::invoke
std::invoke(&Channel_thread::handlersTab[index], this, p.second);
确保 handlersTab 是静态的。 handlersIndexTab 应该也是如此。
根据您的情况,另一种方法是使用枚举而不是字符串作为您的消息,然后打开枚举并直接调用所需的方法。如果消息完全在您的控制之下,包括传输通道,这是最合适的。
如果消息中的描述性字符串很重要,我见过的另一种方法是打开消息的散列。 散列必须是一个 constexpr 函数 以便您的 case 值可以在编译时计算。用法:
switch (hash(p.first))
{
case "channel_setup"_hash:
channelSetupHandler(p.second)
break;
...
default:
// error handling
}
使用这种方法的优点是
- 直接调用需要的方法
- 不需要同步两个列表,实际上既不需要函数列表也不需要查找列表
- 默认大小写可用于处理不良消息
- 更透明的代码
- 易于扩展
我有一个 class,叫做 Channel_thread
。你可以猜到,它的一个函数是线程化的,在这个函数中我想调用另一个成员函数,视情况而定。这就是我使用成员函数数组的原因。
代码如下所示:
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"};
};
我收到此错误:
/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);
如您所见,我在数组中调用成员函数的方式似乎是错误的,可能是因为 static
上下文,我真的不知道,所以我的问题是:
如何从静态函数调用存储在成员函数数组中的成员函数?
提前致谢。
使用 _this->handlersTab[index](p.second);
有几个问题。
使用成员函数指针的语法与使用成员函数的语法不同。成员函数指针在调用之前需要取消引用。给一个成员函数指针,
mfPtr
,使用的语法是(objectPtr->*mfPtr)(...)
。有关详细信息,请参阅 https://en.cppreference.com/w/cpp/language/pointer 中的 成员函数指针 部分。第二个问题是
handlersTab
不是static
的成员变量。要获得指向成员函数的指针,您必须使用_this->handlersTab
.
进行函数调用的一行是:
messageReceived = (_this->*(_this->handlersTab[index]))(p.second);
我建议使用两行来简化它。
fn handler = _this->handlersTab[index];
messageReceived = (_this->*handler)(p.second);
如果您使用的是 c++17,最简单的解决方案是在函数 header.
中使用 std::invokestd::invoke(&Channel_thread::handlersTab[index], this, p.second);
确保 handlersTab 是静态的。 handlersIndexTab 应该也是如此。
根据您的情况,另一种方法是使用枚举而不是字符串作为您的消息,然后打开枚举并直接调用所需的方法。如果消息完全在您的控制之下,包括传输通道,这是最合适的。
如果消息中的描述性字符串很重要,我见过的另一种方法是打开消息的散列。 散列必须是一个 constexpr 函数 以便您的 case 值可以在编译时计算。用法:
switch (hash(p.first))
{
case "channel_setup"_hash:
channelSetupHandler(p.second)
break;
...
default:
// error handling
}
使用这种方法的优点是
- 直接调用需要的方法
- 不需要同步两个列表,实际上既不需要函数列表也不需要查找列表
- 默认大小写可用于处理不良消息
- 更透明的代码
- 易于扩展