使用用户参数作为函数名称及其参数调用函数

时间:2017-09-13 20:50:10

标签: c++ c++11

我是C ++的新手,如果你能帮助我,我将不胜感激。

假设我定义了一些函数:

double square(float x) {return x*x}
double cube (float x) {return x*x*x}
read_lib(const string &file_name)

现在,当我的用户输入square 10时,我想调用square函数,并以10为参数,然后返回100

同样,当我的用户输入cube 3时,我想返回27

同样,当我的用户输入read_lib /path/to/file/library.gz时,我想处理该文件。

这是我的代码:

int main()
{ 
    string quote;
    while(quote != "quit") {

        cout << "Enter: - ";
        string sa[70];
        getline(cin, quote);
        istringstream iss(quote);
        int count = 0;

        while(iss){
            string sub;
            iss>>sub;
            if(sub == "") 
                break;
            sa[count] = sub;
            cout << "sub "<<count <<" is " << sa[count]<<endl;
            count ++; 
        }

        string str = sa[0] + "(" + sa[1] + ")"; 
        // How do I dynamically switch quotations depending on sa[0]
        cout << "command executed was "<< str.c_str() <<endl;
        system(str.c_str());
    }
}

如果这不起作用,我还有什么其他选择来获得预期的结果?

如果我搞得太多,请帮我重新编写这段代码。

这就是它的执行方式:

 sub 0 is cube

 sub 1 is 3

 command executed was cube ("3")

sh: -c: line 0: syntax error near unexpected token `"3"'
sh: -c: line 0: `cube ("3")'

2 个答案:

答案 0 :(得分:2)

您的目标有多个部分:

  • 解析输入。
  • 解析参数以将它们传递给命令函数。
  • 确定要调用的命令函数。
  • 显示结果。

首先,让我们从您要调用的函数开始:

double square(float x) {
    return static_cast<double>(x) * x;
}

double cube(float x) {
    return static_cast<double>(x) * x * x;
}

现在,我们需要一个&#34;命令类型,&#34;我们将其定义为将字符串作为参数并返回字符串的函数:

using command_fn = std::function<std::string(std::string const &)>;

很好,但是我们的功能不接受字符串,而且它们不会返回字符串。无论如何,我们将它们包装在一个lambda中,该lambda使用标准输入流操作符解析参数,并将结果格式化为字符串:

template <typename R, typename A>
command_fn create_command(R (*fn)(A)) {
    return [fn] (std::string const &string_arg) {
        std::istringstream s{string_arg};
        A arg;

        if (!(s >> arg)) {
            return std::string("Failed to convert argument");
        }

        return std::to_string(fn(arg));
    };
}

现在我们可以创建一个std::map<std::string, command_fn>来将命令名映射到包装函数:

std::map<std::string, command_fn> commands{
    { "square", create_command(square) },
    { "cube", create_command(cube) }
};

最后,我们解析输入并在循环中调度调用:

int main() {
    std::string line;

    while (std::getline(std::cin, line)) {
        auto space = line.find(' ');

        std::string cmd, arg;
        if (space == std::string::npos) {
            cmd = std::move(line);
        } else {
            cmd = line.substr(0, space);
            arg = line.substr(space + 1);
        }

        auto const &cmdfn = commands.find(cmd);

        if (cmdfn != commands.end()) {
            std::cout << cmdfn->second(arg) << std::endl;
        } else {
            std::cout << "No such command: " << cmd << std::endl;
        }
    }

    return 0;
}

See a demo

关于此代码的一些注意事项:

  • 我们每个命令只接受一个参数。您可能希望允许多个参数。这可以通过接受create_command()的参数包在A函数中实现。
  • create_command()仅检查转换是否成功。理想情况下,您还需要确保输入字符串完全耗尽。
  • create_command()只会在以下情况下为函数实例化:
    • 该函数的参数是一种有流输入操作符的类型。
    • 返回类型的类型可以传递给std::to_string()

答案 1 :(得分:0)

好的,首先你不需要一个包含70个字符串的数组来解析你的命令。根据您的要求,您似乎需要解析命令然后解析参数。在这种情况下,我使用std :: array来创建一个包含2个字符串的数组。但是,您可以根据需要制作任意数量,然后循环处理命令,而不是手动使用command[0/1]。或者如果需要一个命令,则使用向量,然后使用一些参数。

#include <array>
#include <iostream>
#include <string>

using namespace std;

int main() {
    string quote;
    array<string, 2> command;
    while (quote != "quit") {
        cout << "Enter: ";
        getline(cin, quote);

        auto separator = quote.find(' ');
        if (separator == string::npos) continue;

        command[0] = quote.substr(0, separator);
        command[1] = quote.substr(separator + 1);

        cout << "Command executed was " << command[0] << '(' << command[1] << ")\n";
    }
}

我还使用string.find()方法在已解析的命令中查找空格,然后如果找不到空格,则继续唤醒有效输入。现在,如果用户输入退出,程序仍将退出。在底部,为了清楚起见,它将cout您输入的命令。但是,为了根据输入的内容调用函数,您必须检查command[0]中的字符串是否有效,然后将command[1]中的参数转换为所需的类型。例如,如果需要整数,请使用stoi(s)转换它。