基于用户输入的运行时功能规范

时间:2012-11-02 20:03:15

标签: c++ runtime user-input function-call

好的,因为我用c ++写了很多东西已经有一段时间了,我已经习惯了更现代语言的一些细节。这是一个一直在唠叨我,我相信那里有一个答案。有没有办法在运行时调用用户指定为字符串的函数?不必诉诸某种大规模的开关/ if block?

我所处理的情况可归结为:我已经解决了我在C ++中解决的数学相关问题,并指定为“Problem1.cpp / Problem1.h”,“Problem2。 cpp / Problem2.h“等。每个问题都有一个名为problemX()的函数(其中X是问题的数量),它启动了解决方案。 在程序开始时,我想问用户“你想解决哪个问题?”他们指定了一个数字。然后,我想调用适当的problemX()函数,而不必使用大量的硬编码switch语句(或if语句,或函数指针的索引数组等)。

我确信这是可能的,但我不记得该如何去做。有什么想法吗?

3 个答案:

答案 0 :(得分:5)

unordered_map函数指针的字符串。

调整用户输入以确保它全部为小写(或者如果您喜欢SHOUTING),则只需查找该函数。如果存在则调用它,否则错误。

答案 1 :(得分:1)

C ++没有自动编译或运行时反映其语言中的代码。许多库框架都会对库中的符号进行运行时反映。

解决方案1: 将您的问题粘贴到他们自己的动态库中,让主程序动态加载它们并查找它们导出的符号名称。

解决方案2: 用命名对象替换原始C风格的函数。所以你可能有:

class Problem;
void RegisterProblem( std::string name, Problem const* problem );
std::map< std::string, Problem const* >& GetProblems();
class Problem
{
protected:
  Problem( std::string name ): RegisterProblem( std::move(name), this ) {}
  virtual void operator() const = 0;
  virtual ~Problem() {}
};
class Problem1: public Problem
{
public:
  Problem1():Problem("Problem1") {}
  virtual void operator() const { /* implementation */ }
};

// in .cpp file:
Problem1 problem1Instance();


void RegisterProblem( std::string name, Problem const* problem )
{
  GetProblems()[name] = problem;
}

std::map< std::string, Problem const* >& GetProblems()
{
  static std::map< std::string, Problem const* > problemMap;
  return problemMap;
}

int main()
{
  // parse user input to get this string:
  std::string testInput = "Problem1";

  // run the problem determined by testInput:
  Problem* prob = GetProblems()[testInput];
  Assert(prob);
  (*prob)();
}

上面我们有一些可怕的代码,它们具有自注册问题(在静态映射中注册),以及执行字符串指定的任何问题的main()。

我认为更清洁的方式是:

// In RegisterProblem.h:
// these two have obvious implementations:
std::map< std::string, std::function<void()> >& GetProblems(); 
bool RegisterProblem( std::string s, std::function<void()> ); // always returns true

// In problem1.cpp:
void Problem1(); // implement this!
bool bProblem1Registered = RegisterProblem( "Problem1", Problem1 );
// In problem2.cpp:
void Problem2(); // implement this!
bool bProblem2Registered = RegisterProblem( "Problem2", Problem2 );

// etc

// in main.cpp:
int main(int argc, char** argv)
{
  if (argc == 0)
    return -1; // and maybe print help
  auto it = GetProblems().find( argv[1] );
  if (it == GetProblems().end())
    return -1; // and maybe print help
  it->second(); // call the problem
}

我们取消了不必要的类层次结构,只需在字符串和void()函数之间维护一个映射。此映射的维护将分发到写入函数的每个位置,因此没有集中列表或if语句。

我不会发送任何代码粗糙如上所述,但我希望你明白这一点。

答案 2 :(得分:0)

您应该使用std::map<std::string,_function_pointer_defined_by_you>将函数的名称存储为键,将函数指针存储为值。您还可以使用std::unordered_map<std::string,_function_pointer_defined_by_you>,类似std::hash_map。如果你可以使用C ++ 11,你会在标题文件std::unordered_map找到<unordered_map>,如果你不能在<tr1/unordered_map>找到。{1}}。有关map和unordered_map的文档可以在以下位置找到: