我正在尝试制作字符串函数的哈希图
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;
}
我正在尝试制作一个映射,它存储一个字符串作为标识符和一个函数,该函数 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;
}