具有可变数量参数但没有任何显式参数的函数

Function with a variable number of parameters without any explicit parameters

本文关键字:参数 任何显 函数      更新时间:2023-10-16

如何在C++中使用以下形式的函数:void function(...) {}

确实需要至少一个隐式参数吗?

从注释重复:

C99和C++11之间似乎有一个有趣的区别:C++11允许函数声明void foo(...),因为参数声明子句中的函数声明列表是可选的:[dcl.fct]

功能声明:

D1 (参数声明子句)cv限定符seqoptref限定符opt异常规范option属性说明符seqopt

参数:

参数声明子句:
参数声明列表opt...opt
参数声明列表, ...

(请注意参数声明列表...在此处分别为opt,这意味着您可以省略其中一个或另一个或两者。clang++和g++支持此解释。)

在C99中,不允许此声明,因为参数列表的参数类型列表:6.7.5/1 中不是可选的

功能声明:

直接声明符(参数类型列表)

参数:

参数类型列表:
参数列表
参数列表, ...

由于va_start等宏/函数是从C99继承的,因此在C++中,无法使用与省略号匹配的参数和空的参数声明列表


C99:7.15.1.4 中va_start的描述

void va_start(va_list ap,parmN);
[…]
参数parmN是变量中最右边参数的标识符函数定义中的参数列表, ...之前的那个)。[…]

强调我的。C99假设省略号之前有一个参数,因为在C99中声明一个带有省略号但没有参数的函数是不合法的。


然而,我可以看到使用带省略号但在C++中没有任何参数的函数的两个原因:

  • 过载解决方案。将参数与省略号匹配会导致重载的排名非常低:省略号转换序列比任何用户定义的标准转换序列都差[over.ics.rank]/2。这对元编程很有用:

    char foo(int);
    int  foo(...);
    struct S{};
    S s;
    sizeof(foo(42));    // yields 1
    sizeof(foo(s));     // yields sizeof(int)
    
  • 实现定义的技巧。您的实现可能提供了访问那些与省略号匹配的参数的方法。例如,参见BobTFish的示例

如果您想保持某种平台独立性,您至少需要一个参数并使用va_arg宏。

如果您知道体系结构和调用约定的低级别细节,那么您可以直接从寄存器和/或堆栈中提取参数(取决于各种参数的最终位置)。

鉴于va_start"函数"需要一个参数来设置va_list,我认为不可能以可靠且可移植的方式来实现这一点。很可能找到在特定平台上有效的东西,但如果您更改编译器,为不同的平台编译,在某些情况下,即使您使用不同的编译器选项进行编译(或更改函数中的代码,例如引入局部变量),也不要指望它能起作用。

... 
va_list vl;
va_start(vl, arg);
...

当然,你的另一个问题是知道什么时候没有争论(这将是一个有效的案例)。所以,如果你至少没有一个论点,那么当你根本没有通过任何论点时会发生什么?你是怎么"知道"这种情况的?