【问题标题】:C++ - Call input function as a stringC++ - 以字符串形式调用输入函数
【发布时间】:2025-11-29 18:20:09
【问题描述】:

我是 C++ 新手,我正在编写一个执行某些命令的程序。我的程序应该有大约 200 个命令,并使用 strcmp 检查字符串是否是命令之一,这对我来说似乎很慢且不准确。我想知道是否有一个函数可以直接调用给定的输入作为命令。

例如:

void main() {    
    char test[60], param[10];
    std::cin >> test >> param;
    callFunction(test, param); 
}

注意:我已经进行了一些搜索并找到了一种使用映射的方法,但是如果每个函数的参数数量不同怎么办?任何帮助将不胜感激,谢谢!

【问题讨论】:

  • 您可以使用函数指针将函数绑定到映射中的每个单词并相应地调用该函数,但这确实需要您的参数相同。只需将给定的参数传递给您的函数并在那里提取它们。

标签: c++ string function maps std


【解决方案1】:

您可以使用所需的参数调用 exec 方法来运行您的命令

结帐:http://linux.die.net/man/3/exec

【讨论】:

    【解决方案2】:

    查看命令模式:

    将所有命令/函数封装在它们自己的对象中。很可能,您不需要 200 个不同的 Command 类,而只需要几个,将具有相同目的、参数计数和类型的相似函数调用分组。

    然后将字符串映射到这些命令对象。命令对象都具有相同的接口,并且封装了原始函数的参数数量和类型的差异。

    【讨论】:

      【解决方案3】:

      函数调用表(或类似表)。如果速度很重要,请使用std::unordered_map 执行以下操作:

      std::unordered_map<std::string, function> cmds;
      ...
      cmds["mycommand"] = myCommandFunction();
      

      我个人也用字符串 + 函数指针的静态数组表编写了十几个不同的程序,并且只使用一个普通循环来迭代数组 - 它通常不是设计中最慢的部分 [如果速度很重要,配置文件你的代码看看它在哪里花费时间,然后进行优化,但首先要编写清晰简单的代码,不要仅仅因为你认为它可能需要很大一部分时间而使代码更复杂,然后才测量它]

      可以在此处找到使用 std::map 和函数指针 [在本例中为 lambda 函数] 的示例: https://github.com/Leporacanthicus/lacsap/blob/master/builtin.cpp#L972

      【讨论】:

        【解决方案4】:

        我的评论示例:

        #include <string>
        #include <unordered_map>
        #include <iostream>
        
        typedef void(*commandPtr)(const char* args);
        
        std::unordered_map <std::string, commandPtr> commands;
        
        void someCommand(const char* args)
        {
            std::cout << "some command with args : " << args << std::endl;
        }
        
        int main()
        {
            commands.insert(std::make_pair("someCommand", someCommand)); // add a command to the map
            std::string command, args;
            std::cin >> command >> args;
            if (commands.find(command) == commands.end()) // the command doesn't exist
                std::cout << "Command doesn't exist";
            else
                commands.find(command)->second(args.c_str()); // call the command with args
            std::cin.get();
            return 0;
        }
        

        不过,这仅允许一个任意参数。

        【讨论】:

          【解决方案5】:

          为每个命令创建一个类并从一个公共基类继承这些类是一个很好的编码实践,其中一个虚函数采用参数向量。在您的情况下,参数是字符串,因此命令处理方法可以将字符串向量作为参数并返回例如程序退出代码。然后是一个映射,更具体地说是一个哈希表,它在 C++ 中是 unordered_map,因为这里似乎不需要有序迭代。在该 unordered_map 中,键是小写的命令名称,值是指向处理该命令的类的实例的指针。源代码示例如下:

          #include <unordered_map>
          #include <string>
          #include <cstdint>
          #include <vector>
          #include <iostream>
          #include <memory>
          
          enum class ExitCode : int32_t
          {
              OK = 0,
              WRONG_USAGE = 1,
              // Change the values below to your specific error (exit) codes
              SOME_ERROR = 2,
              OTHER_ERROR = 3
          };
          
          class CommandProcessor
          {
          public:
              virtual ExitCode Go(const std::vector<std::string>& parameters) = 0;
          };
          
          class FooCommandProcessor : public CommandProcessor
          {
          public:
              virtual ExitCode Go(const std::vector<std::string>& parameters) override
              {
                  // Implement processing of Foo command here
                  return ExitCode::OK;
              }
          };
          
          class BarCommandProcessor : public CommandProcessor
          {
              virtual ExitCode Go(const std::vector<std::string>& parameters) override
              {
                  // Implement processing of Bar command here
                  return ExitCode::OK;
              }
          };
          
          // Implement classes processing the other commands here
          
          class CommandSelector
          {
              typedef std::unordered_map<std::string, std::shared_ptr<CommandProcessor>> 
                  StringCommandProcessorMap;
              StringCommandProcessorMap _scpm;
              template <class CP> void RegisterCommand(const std::string& command)
              {
                  _scpm.insert(StringCommandProcessorMap::value_type(
                      command, std::shared_ptr<CommandProcessor>(new CP())));
              }
          public:
              CommandSelector()
              {
                  RegisterCommand<FooCommandProcessor>("foo");
                  RegisterCommand<BarCommandProcessor>("bar");
                  // Register the rest of your commands here
              }
              ExitCode InvokeCommand(const std::string& command, 
                  const std::vector<std::string>& parameters)
              {
                  std::string lowercaseCommand;
                  for (int i = 0; i < int(command.size()); i++)
                  {
                      lowercaseCommand.push_back(::tolower(command[i]));
                  }
                  StringCommandProcessorMap::iterator it = _scpm.find(lowercaseCommand);
                  if (it == _scpm.end())
                  {
                      std::cout << "Unknown command: " << lowercaseCommand << std::endl;
                      return ExitCode::WRONG_USAGE;
                  }
                  return it->second->Go(parameters);
              }
          };
          
          int main(int argc, char* argv[])
          {
              if (argc < 2)
              {
                  std::cout << "Usage: <your_exe_name> <command> [arguments]" << std::endl;
                  return int(ExitCode::WRONG_USAGE);
              }
              std::string command(argv[1]);
              std::vector<std::string> parameters;
              for (int i = 2; i < argc; i++)
              {
                  parameters.push_back(std::string(argv[i]));
              }
              CommandSelector cs;
              ExitCode ec = cs.InvokeCommand(command, parameters);
              return int(ec);
          }
          

          【讨论】: