我正在尝试制作字符串函数的哈希图

I am trying to make a hashmap of of string functions

我正在尝试制作一个映射,它存储一个字符串作为标识符和一个函数,该函数 returns 一个字符串我已经尝试过 typedef 但我一直 运行 遇到问题,因为我无法转换我的 typedef string (command)() 到常规字符串 我也尝试过 map 命令,但它给了我一个表达式预期错误,但如果我用 int 替换字符串,它确实有效。有人知道这样做的方法吗?这就是我的代码的样子

        #include "iostream"
        #include <map>
        #include <functional>


        using namespace std;

        class GameController {

        public:
            void inputReader();

        private:


            bool gameOver = false;
            map<string,string(*)()> commands;//Does not work

            //commands
            string  commandReader(string* inputCommand);
            void initCommands();

            //both
            char* end();
            string run();

            //while attacking
            string attack();
            string usePotion();
            string useItem();

            //while in room
            string engage();
            string searchRoom();
            string rest();
            string checkBag();
            string checkMap();
            string checkStats();
            //string save();



        };



        #endif //ROGUE_GAMECONTROLLER_H

    #include "GameController.h"

    GameController::GameController(){
        initCommands();
    }
void GameController::inputReader() {

while (!gameOver){
    string x;
    getline(cin,x);
    cout << commandReader(&x) << endl;
    }

}

string  GameController::commandReader(string *inputCommand) {

    for (map<string,string>::iterator it = commands.begin(); it!=commands.end(); ++it)
    {
        if(it->first == *inputCommand)
        {
            return it->second;
        }

    }
    return "Computer says no type help for commands";
}

    void GameController::initCommands() {


        commands["end"] = end;
        //while attacking
        commands["run"] = run;
        commands["attack"] = attack;
        commands["use potion"] = usePotion;
        commands["use item"] = useItem;

        //while in room
        commands["engage"] = engage;//TODO
        commands["search"] = searchRoom;
        commands["rest"] = rest;
        commands["check bag"] = checkBag;
        commands["map"] = checkMap;
        commands["stats"] = checkStats;
    }

指向成员函数的指针不同于指向自由函数甚至静态方法的指针。一方面,所有成员函数在函数参数中都有一个隐藏的 this 指针,这使得所有这个对象神奇地起作用。

逐步完成:

首先,定义一个助手:

typedef string (GameController::*funcp)();

这定义了 funcp 类型,它表示指向 GameController 的成员函数的指针(部分地解决了 this 问题),它不带参数并且 returns string

然后,修改您的地图以使用 funcp

map<string, funcp> commands;

然后你必须稍微更改成员函数的赋值,以粗暴地明确它是一个指针并且是 GameController

的成员
commands["end"] = &GameController::end;

您还可以为自己省去一些运行时麻烦,并在此处使用初始化列表,而不是在每个 GameController 对象中使用函数和映射。这需要一些额外的解释,而且我必须在几分钟内动身。对于那个很抱歉。不过,静态初始化的静态地图确实更好,值得您花时间研究。

我从 C++ Super FAQ 偷来的下一位。阅读此 link。值得一读,因为它可以解决你的很多问题。

#define CALL_MEMBER_FN(object,ptrToMember)  ((object).*(ptrToMember))

这使得调用该函数非常容易。

return CALL_MEMBER_FN(*this, it->second)();

这应该可以为您完成。

编辑:

Tweej 在他们的回答中展示了通常更好的方法来做到这一点,std::function 和 std::bind。既然是崇尚古法,那我就解释一下吧。

两个原因:一是隧道视野直接回答OP的问题。

第二个是使用古老的方法,我可以轻松地使 commands 静态化,而无需为 GameController 的每个实例创建一个新的 commands 副本。当使用std::bind时,你必须有绑定的对象,这破坏了静态的想法。

探索仅使用 std::function 的想法似乎已经结出硕果,并使古老的方式变得过时。 CALL_MEMBER_FN 宏不见了。 funcp typedef

不见了

地图现在被定义为静态的,这是我针对旧的 C++11 之前的方法的目标。请注意,funcp typedef 被一个函数替换,该函数接受指向 GameController 的指针以提供 this.

static map<string, std::function<string(GameController*)>> commands;

并且地图现在被设置为使用静态初始值设定项列表。不需要功能。这个初始化程序需要位于 class 定义之外,因为......我不确定为什么。我认为这在 C++14 中有所改变。

map<string, std::function<string(GameController*)>> GameController::commands
{
    {"end", &GameController::end},
    {"run", &GameController::run},
    {"attack", &GameController::attack},
    {"use potion", &GameController::usePotion},
    {"use item", &GameController::useItem},
    {"engage", &GameController::engage},
    {"search", &GameController::searchRoom},
    {"rest", &GameController::rest},
    {"check bag", &GameController::checkBag},
    {"map", &GameController::checkMap},
    {"stats", &GameController::checkStats}
};

地图只初始化一次。所有 GameControllers 都将使用相同的 commands,所以构造函数真的很笨

GameController::GameController()
{
    // init function is gone
}

命令 reader 被大肆宣传,主要是因为地图的重点是您可以通过按键搜索它。所以我搜索密钥而不是迭代。函数调用现在很明显而且非常简单:

string GameController::commandReader(const string &inputCommand)
{
    map<string, std::function<string(GameController*)>>::iterator found = commands.find(inputCommand);
    if (found != commands.end())
    {
        return found->second(this);
    }
    return "Computer says no type help for commands";
}

这个问题被标记为 C++11,所以这里有一个使用 unordered_map 的简明示例(一个真正的哈希映射,不像 std::map 我的 STL 参考文献说通常使用二叉搜索树实现), 和 std::function.

#include <iostream>
#include <functional>
#include <string>
#include <unordered_map>

std::string foo()
{
   return "foo!";
}

struct MyClass
{
   static std::string bar()
   { return "bar!"; }

   std::string FizzBuzz() const
   { return "FizzBuzz!"; }

   std::string operator()() const
   { return "Myclass!"; }
};


int main(int argc, char **argv)
{
   MyClass mc;

   std::unordered_map<std::string, std::function<std::string()>> commands;

   commands["myfoo"]   = foo;
   commands["mybar"]   = MyClass::bar;
   commands["myfb"]    = std::bind(&MyClass::FizzBuzz, mc);
   commands["myclass"] = mc;

   for( const auto &f : commands)
      std::cout << f.second() << std::endl;

   std::cout << commands["myfoo"]() << std::endl;

   return 0;
}