Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/127.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/svg/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 基于字符串选择成员函数_C++_Hashmap_Function Pointers_Dispatch_Member Function Pointers - Fatal编程技术网

C++ 基于字符串选择成员函数

C++ 基于字符串选择成员函数,c++,hashmap,function-pointers,dispatch,member-function-pointers,C++,Hashmap,Function Pointers,Dispatch,Member Function Pointers,我有一组硬件处理程序类,都是从基类派生的,它们必须响应传入的数据包。此数据包的一部分是ASCII字符串,它确定硬件处理程序的哪个成员函数用于处理数据包(例如,“fan”将执行ToggleFan()函数) class HardwareHandler { virtual void dispatchCommand(const String& cmd) = 0; } class FooblerHandler : public HardwareHandler { void to

我有一组硬件处理程序类,都是从基类派生的,它们必须响应传入的数据包。此数据包的一部分是ASCII字符串,它确定硬件处理程序的哪个成员函数用于处理数据包(例如,“fan”将执行
ToggleFan()
函数)

class HardwareHandler {
    virtual void dispatchCommand(const String& cmd) = 0;
}

class FooblerHandler : public HardwareHandler {

    void toogleFan();

    void dispatchCommand(const String& cmd) {
        //is this a "good" way to do this?
        if (cmd == "fan")
            toggleFan();
    }
}
我使用JUCE作为框架,这意味着我有模板化的
HashMap
s和
String

但是,我很难找到一种基于这个字符串选择正确处理函数的方法

if (str == "hello")
    FooCommand();
else if (str == "bar")
    BarCommand();
在我看来,这在概念上很难看,因为其中有很多相对昂贵的字符串比较。但是,代码很容易编写,并且每个类的逻辑都保存在一个地方

我尝试过的另一种方法是将字符串的哈希映射到枚举,并在switch语句中使用该映射:

switch (str.getHash())
{
case CmdFoo:
    FooCommnad();
    break;
....and so on
}
然而,这也需要我设置一个静态哈希映射,以及维护开关以匹配

我还尝试了一个从字符串到成员函数指针本身的散列映射,希望能够直接从字符串跳到成员函数,而无需在case语句中列出它们,并且还允许一个非常通用的分派函数,因为它只需要在散列映射中查找,甚至不需要知道所有操作选项-它们可以单独包含在哈希映射中,允许我将分派函数推到基本处理程序类中,而不是在每个特定的设备处理程序中重复我自己。但是,这个方法一直困扰着我,因为我不知道如何正确地做这件事,或者即使可以使用静态哈希映射和成员函数来做这件事纳什


是否有一种惯用的方法基于字符串(或类似的难以比较的类型)分派给成员函数,最好使用尽可能多的逻辑进行泛型并移动到父类?

我认为处理此问题最有效的方法是创建一个
std::map
,将字符串映射到适当的函数中。该方法速度快(由于对数搜索算法),简单安全

class FooblerHandler : public HardwareHandler {
   typedef void (HardwareHandler::*function)();
   map<string,function> commandMap;

   void dispatchCommand(const string& cmd) {
      if(commandMap.count(cmd))
         (this->*commandMap.find(cmd)->second)();
      else
         cout << "No command found with name \"" <<cmd<< "\"." << endl;
   }
};
并且包含在几乎所有IDE提供的标准模板库(STL)中

编辑:
我没有完全阅读最后的文本。现在你知道了语法:)

我认为处理这个问题最有效的方法是创建一个
std::map
,它可以将字符串映射到适当的函数中。该方法快速(由于采用对数搜索算法),简单安全

class FooblerHandler : public HardwareHandler {
   typedef void (HardwareHandler::*function)();
   map<string,function> commandMap;

   void dispatchCommand(const string& cmd) {
      if(commandMap.count(cmd))
         (this->*commandMap.find(cmd)->second)();
      else
         cout << "No command found with name \"" <<cmd<< "\"." << endl;
   }
};
并且包含在几乎所有IDE提供的标准模板库(STL)中

编辑:
我没有完全读完最后的课文。好了,现在你知道语法了:)

这是我的尝试。您可以将映射机制封装到类中:

#include <iostream>
#include <string>
#include <functional>
#include <map>

class X;

template<class X>
class handler_factory;

template<>
class handler_factory<X>
{
private:
    using HandlerType = void (X::*)();
public:
    handler_factory();

    HandlerType get(const std::string& name) const
    {
        if (handlers.find(name) == handlers.end())
            return nullptr;
        else
            return (*handlers.find(name)).second;
    }
private:
    std::map<std::string, HandlerType> handlers;
};

class X
{
public:
    friend class handler_factory<X>;
private:
    void f();
    void h();
};

handler_factory<X>::handler_factory()
{
    handlers["f"] = &X::f;
    handlers["h"] = &X::h;
}

void X::f() { std::cout << "X::f();"; }
void X::h() { std::cout << "X::h();"; }
其中,
find\u handler
被定义为私人助手方法:

private:
    auto find_handler(const std::string& name)
        -> decltype(handler_factory<X>().get(name))
    {
        return handler_factory<X>().get(name);
    }
private:
自动查找\u处理程序(const std::string和name)
->decltype(handler_factory().get(name))
{
返回处理程序_factory().get(名称);
}

这是我的尝试。您可以将映射机制封装到类中:

#include <iostream>
#include <string>
#include <functional>
#include <map>

class X;

template<class X>
class handler_factory;

template<>
class handler_factory<X>
{
private:
    using HandlerType = void (X::*)();
public:
    handler_factory();

    HandlerType get(const std::string& name) const
    {
        if (handlers.find(name) == handlers.end())
            return nullptr;
        else
            return (*handlers.find(name)).second;
    }
private:
    std::map<std::string, HandlerType> handlers;
};

class X
{
public:
    friend class handler_factory<X>;
private:
    void f();
    void h();
};

handler_factory<X>::handler_factory()
{
    handlers["f"] = &X::f;
    handlers["h"] = &X::h;
}

void X::f() { std::cout << "X::f();"; }
void X::h() { std::cout << "X::h();"; }
其中,
find\u handler
被定义为私人助手方法:

private:
    auto find_handler(const std::string& name)
        -> decltype(handler_factory<X>().get(name))
    {
        return handler_factory<X>().get(name);
    }
private:
自动查找\u处理程序(const std::string和name)
->decltype(handler_factory().get(name))
{
返回处理程序_factory().get(名称);
}

std::map
?你所有的方法都返回
void
?不,在现实生活中它们返回
bool
。那么
std::map
呢?你所有的方法都返回
void
?不,他们在现实生活中返回
bool
handler\u工厂
是否必须专门针对
HardwareHandler
(例如
FooblerHandler
barrierhandler
等)的每个子类?是的,但这只是为了方便。不同的类可能具有不同的成员函数签名。如果不需要,则处理程序工厂不需要模板化,但可以是一个常规类。@实际上,您不需要。如果
Bar
是一个继承自
Foo
的类,而
X
是一个专门用于
Foo
的类,
X
可以正常工作。
handler\u factory
是否必须专门用于
HardwareHandler
的每个子类(例如,
FooblerHandler
BarrifierHandler
等)?@icpiveload是的,但这只是为了方便。不同的类可能有不同的成员函数签名。如果没有,则
handler\u factory
不需要模板化,而可以是一个普通类。@icpiveload说明:实际上,您没有。如果
Bar
是从
Foo
继承的类,则
X
是一个专门用于
Foo
的类,
X
可以正常工作。