C ++ - 将输入函数调用为字符串

时间:2015-06-27 07:33:16

标签: c++ string function maps std

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

例如:

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

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

5 个答案:

答案 0 :(得分:1)

为每个命令创建一个类并使用带有参数向量的虚函数从公共基类继承这些类将是一个很好的编码实践。在您的情况下,参数是字符串,因此命令处理方法可以将字符串向量作为参数并返回,例如程序退出代码。然后是一个地图,更具体地说是一个哈希表,它是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);
}

答案 1 :(得分:0)

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

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

答案 2 :(得分:0)

查看命令模式:

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

然后为这些命令对象创建字符串映射。命令对象都具有相同的接口,并且原始部分的参数计数和类型的差异被封装在其中。

答案 3 :(得分:0)

函数调用表(或类似函数)。如果速度很重要,请使用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 :(得分:0)

我的评论示例:

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

这只允许一个abitrary参数。