【问题标题】:How to use member functions array in a static function?如何在静态函数中使用成员函数数组?
【发布时间】:2018-12-31 02:19:51
【问题描述】:

我有一门课,叫做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-&gt;*handlersTab[index])(p.second);
  • 好吧,我试过了,但又导致了另一个错误:error: invalid use of member 'Channel_thread::handlersTab' in static member function messageReceived = _this-&gt;*handlersTab[index](p.second);.
  • 您不能从静态方法访问非静态成员(没有一些显式指针或对 this 以外的实例的引用)。因此,您要么需要将成员设为静态,要么以某种方式获取要使用的实例。
  • 这种情况下需要使用(_this-&gt;*(_this-&gt;handlersTab[index]))(p.second);
  • 我会使用 std::mapstd::unordered_map 而不是 2 个容器。也许对于 4 种方法,效率无关紧要,但这会更清洁、更高效。

标签: c++ static boost-thread member-function-pointers


【解决方案1】:

如果您使用的是 c++17,最简单的解决方案是在函数标头中使用 std::invoke。

std::invoke(&Channel_thread::handlersTab[index], this, p.second);

确保 handlersTab 是静态的。 handlersIndexTab 也应该如此。

根据您的情况,另一种方法是使用枚举而不是字符串作为您的消息,然后打开枚举并直接调用所需的方法。如果消息完全在您的控制之下,包括传输通道,这是最合适的。

如果在消息中包含描述性字符串很重要,我见过的另一种方法是打开消息的散列。 散列必须是一个 constexpr 函数,以便您的案例值可以在编译时计算。用法:

switch (hash(p.first))
{
case "channel_setup"_hash:
    channelSetupHandler(p.second)
    break;
...
default:
    // error handling
}

使用这种方法的优点是

  • 所需方法的直接调用
  • 不需要同步两个列表,实际上函数列表和查找列表都不需要
  • 默认情况可用于处理不良消息
  • 更透明的代码
  • 易于扩展

【讨论】:

    【解决方案2】:

    使用_this-&gt;handlersTab[index](p.second);有几个问题。

    1. 使用成员函数指针的语法不同于使用成员函数。成员函数指针在被调用之前需要被取消引用。给一个成员函数指针,mfPtr,使用的语法是(objectPtr-&gt;*mfPtr)(...)。有关详细信息,请参阅https://en.cppreference.com/w/cpp/language/pointer 上的指向成员函数的指针部分。

    2. 第二个问题是handlersTab不是static成员变量。要获得指向成员函数的指针,您必须使用_this-&gt;handlersTab

    进行函数调用的唯一方法是:

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

    我建议用两行来简化它。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-19
      • 1970-01-01
      相关资源
      最近更新 更多