我正在尝试创建一个存储字符串作为标识符的映射,以及一个返回字符串的函数我尝试过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;
}
答案 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";
}