【问题标题】:Variable parameter lists in C++ and CC++ 和 C 中的可变参数列表
【发布时间】:2009-10-07 05:50:56
【问题描述】:

我正在用 C++ 重写一个 C 程序以利用 OO 方面的优势,以便它可以轻松支持多种设备,并且程序的一部分是表达式评估器。表达式可以有函数调用,下面是函数的结构。

typedef struct {
    char *name;
    int argc;
    void (*func) ();
} FUNCTION;

func 可以通过它传递可变数量的参数。

RESULT *param[10];

if (Root->Function->argc < 0) {
    /* Function with variable argument list:  */
    /* pass number of arguments as first parameter */
    Root->Function->func(Root->Result, argc, &param);
} else {
    Root->Function->func(Root->Result, param[0], param[1], param[2], param[3], param[4], param[5], param[6],
                         param[7], param[8], param[9]);
}

老实说,我什至不确定如何在 C 中做到这一点。一个解释会很好。可以用 C++ 完成吗?

【问题讨论】:

    标签: c++ c parameters optional-parameters


    【解决方案1】:

    var args 是您正在寻找的。它适用于 C 和 C++。这是用于printf() 的内容,例如:)。

    您可以通过googling va_arg(用于可变数量参数的函数之一)找到更多信息

    【讨论】:

    • 注意变量参数的限制。您不能通过省略号传递任何类型的对象。
    • @DavidRodríguez-dribeas 你能传递什么样的东西?
    • @JohnLeidegren:除了在 TMP 中,我倾向于避免省略号,所以我不确定所有细节,但一般的想法是你不能传递任何没有简单复制构造函数的类型,可能是析构函数...不确定是否还有其他限制。
    • @DavidRodríguez-dribeas 我确实在 MSDN 上找到了一些关于该主题的文档,但不确定是否微不足道。它表示这只是一个 memcpy 操作。约束必须仅类似于 POD。 va_arg 函数仅支持等效的 memcpy。如果我理解正确的话,没有可构造的副本,也不是微不足道的。
    【解决方案2】:

    实际上,我要与这里的每个人以及你的愿望作对。

    省略号是错误的。它在 C 中被认为是不可或缺的,但从那时起我们学得更好。

    确实,在 C++ 中使用对象(例如,函数对象)确实有很多方法可以做得更好。

    您正在寻找的是Command Pattern

    创建一个名为“Command”的基类(与 execute() 方法的接口),然后为您要放入“void (*func)()”中的每个“函数”创建一个派生类。

    现在,您的代码将如下所示:

    std::vector<RESULT*> param(10, NULL);
    
    if (Root->Function->argc < 0) {
        /* Function with variable argument list:  */
        /* pass number of arguments as first parameter */
        Command1* aCommand = new Command1(Root->Result);
        aCommand->set(Root->Result, argc, &param);
        Root->Function->command = aCommand;
        Root->Function->command->execute();
    } else {
        Command2* aCommand = new Command2(Root->Result);
        aCommand->set(Root->Result, param[0], param[1], param[2], param[3], param[4], param[5], param[6], param[7], param[8], param[9]);
        Root->Function->command = aCommand;
        Root->Function->command->execute();
    }
    

    这里你不需要省略号,因为每个命令对象都是专门的,并且确切地知道它需要什么参数(数字和类型)。

    命令模式让您拥有“...”(省略号)的所有好处,而不会带来不便。好吧,当然有些人会说这是浪费时间,因为他们无论如何都不会犯错,所以他们不需要输入更多......不幸的是我没有那么聪明,所以我更喜欢定义约束(数字,类型, 断言)并让编译器为我强制执行它们。

    【讨论】:

    • 变量参数列表可以在 C++ 中使用与 var_args 相同的调用者语法来实现。被调用的函数必须被多次定义,但可以保留方便的语法。见ddj.com/cpp/184401999
    • 但同时,可变参数列表在调用代码中不必要地引入了复杂性,同时完全避开了类型安全。命令模式或它的一些变体在各个方面都优于 C++ 中的变量参数列表。在 C 中,它或多或少是唯一的选择。
    【解决方案3】:

    您可以在 C++ 中通过在参数列表中使用 ... 来实现。看看here 的解释。但我认为如果你只是将参数向量传递给你的函数会更好。

    【讨论】:

      【解决方案4】:

      请记住,函数只是另一个地址,在调用 start 时从堆栈中获取输入参数。因此,当您声明一个 FUNCTION 时,您只是存储了该函数的地址。使用该地址,以后可以使用不同的参数调用该函数。是的,它可以通过使用参数列表在 C++ 中完成,但是实现取决于您希望它如何处理它。

      【讨论】:

        【解决方案5】:

        就个人而言,在评估表达式的 AST 时,我倾向于使用特定领域的语言来为我生成 AST 节点结构的层次结构和一组多分派操作。我有我自己的 DSL,但这个想法是从 treecc 偷来的。很多问题都消失了,因为您不需要单个节点类或单个评估节点函数 - 并且使用 DSL 为您进行各种检查,您通常可以避免用不同的问题替换这些问题。

        treecc 可以生成 C 或 C++ 输出(或其他几种语言)IIRC。这很像使用 flex 或 bison。生成的代码有点幼稚,你很快就会希望对继承有更多的控制,但它工作得很好。

        【讨论】:

          猜你喜欢
          • 2012-10-01
          • 2011-02-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-09-13
          • 2010-12-12
          • 1970-01-01
          相关资源
          最近更新 更多