在不传递参数数量且只有3个点的情况下,如何使用变差函数

How would it be possible to use variadic function without passing number of arguments and only with 3 dots?

本文关键字:情况下 何使用 函数 3个 参数 数数      更新时间:2023-10-16

考虑到下面的代码,是否可以在不获取参数数量的情况下定义一个可变函数?

void printFunction(...)
{
int noOfArgs = "Any way to get number of arguments?";
va_list args;
va_start(args, noOfArgs);
cout << va_arg(args, int) << endl;
for (int i = 2; i <= noOfArgs; i++)
{
cout << va_arg(args, int) << endl;
}
va_end(args);
}

int main()
{
printFunction(1, 2, 3, 4, 5);
return 0;
}

在Cva_args中无法获取参数的数量。你能做的最好的事情就是使用一个结束序列的神奇值和一个宏来向用户隐藏它:

#define printFunction(...) actualPrintFunction(__VA_ARGS__, 42)
void actualPrintFunction(int first, ...)
{
va_list args;
va_start(args, first);
int arg;
std::cout << first << endl;
while((arg = va_arg(args, int)) != 42)
{
cout << arg << endl;
}
va_end(args);
}

正如评论中提到的,您也可以使用C++折叠表达式。上面的优点是与C兼容,编译速度更快,而C++方法为您提供了类型安全

在C++11及以后的版本中,这很容易:

template<typename... Arguments>
void printFunction(Arguments &&...args) {
auto noOfArgs = sizeof...(Arguments);

然而,您使用的是一种老风格,即普通C,预处理器宏风格,这是非常不同的。首先,要使用预处理器宏,您需要至少有一个命名参数,该参数将用于启动va_list,这是复杂性的开始。

我认为没有标准的方法来计算参数的数量,它可以通过多种方式实现,如果这是你真正想要的,我会将其标记为C而不是C++

如何进入争论:有两种选择,让我们称之为"机关枪"answers"滴滴答答"——这是我的名字——:

#include <utility>
template<typename... Ts>
void ignoreResults(Ts &&...) {}
template<typename Argument>
int machineGunBullet(Argument &&arg);
inline void drip() {} // do nothing
template<typename A1, typename... Tail>
void drip(A1 &&a1, Tail &&...tail) {
// do something here with a1
drip(std::forward<Tail>(tail)...);
}
template<typename... Arguments>
void printFunction(Arguments &&...args) {
ignoreResults(machineGunBullet(std::forward<Arguments>(args))...);
// or
drip(std::forward<Arguments>(args)...);
}

这建立在编译器资源管理器中,https://godbolt.org/z/aSx2wv

从技术上讲,有一种方法类似于获取以null结尾的字符串的长度:使用特定的参数值来指定参数列表的末尾。

但是,请注意,为了使用va_start,必须至少有一个命名参数。在您的示例中,您试图将一个局部变量传递到va_start中,这是不允许的。该宏不接受"参数的数量"。它采用"可变参数开始之前的最后一个命名参数"。

也就是说:我建议不要使用C风格的变分函数。