我正在尝试制作字符串函数的hashmap

时间:2015-11-03 21:30:01

标签: c++ c++11 c++-standard-library

我正在尝试创建一个存储字符串作为标识符的映射,以及一个返回字符串的函数我尝试过typedef但是我一直遇到问题,因为我无法转换我的typedef字符串(命令)()到一个常规的字符串我也尝试过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;
    }

2 个答案:

答案 0 :(得分:2)

这个问题标记为C ++ 11,所以这里是一个简洁的例子,它使用unordered_map(一个真正的哈希映射,不像std :: map,我的STL引用通常用二叉搜索树实现)和std ::功能。

#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;
}

答案 1 :(得分:1)

指向成员函数的指针不像指向自由函数甚至静态方法的指针。首先,所有成员函数在函数参数中都有一个隐藏的this指针,这使得所有这个对象变得神奇。

一步一步地进行:

首先,定义一个帮手:

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

这定义了类型funcp,它表示指向GameController的成员函数的指针(部分处理this问题),该函数不带参数并返回string

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

map<string, funcp> commands;

然后你必须稍微更改一下成员函数的赋值,以便它是一个指针和GameController的成员

commands["end"] = &GameController::end;

您还可以节省一些运行时故障,并在此使用初始化列表,而不是每个GameController对象中的函数和映射。这需要一些额外的解释,我必须在几分钟内继续前进。对于那个很抱歉。静态地图的静态地图确实更好,值得您花时间研究。

我从C++ Super FAQ偷走了下一个位。阅读此链接。值得一读,因为它会解决你将遇到的很多问题。

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

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

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

这应该是为你做的。

编辑:

Tweej在他们的回答中演示了通常更好的方法,std :: function和std :: bind。既然我在倡导古老的方式,我想解释一下原因。

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

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

探讨仅仅使用std :: function的想法似乎已经结出果实并且在古老的方式上已经过时了。消失的是CALL_MEMBER_FN宏。 funcp typedef

已经不见了

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

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

现在该地图已被操纵以使用静态初始化列表。无需任何功能。这个初始化程序需要位于类定义之外,因为...我不知道为什么。我认为这在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
}

命令阅读器得到了很大的提升,主要是因为地图的点是你可以通过键搜索它。所以我搜索密钥而不是迭代。函数调用现在很明显而且很简单:

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";
}