Reputation: 33
Considering the code below, is it possible to define a variadic function without getting number of arguments?
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;
}
Upvotes: 2
Views: 2521
Reputation: 1242
In C++ 11 and after, it is very easy:
template<typename... Arguments>
void printFunction(Arguments &&...args) {
auto noOfArgs = sizeof...(Arguments);
However, you are using an old-style, plain-C, preprocessor macro style, which is very different.
First, to use the preprocessor macros you need to have at least one named parameter, which will be used to start the va_list
, and that's the beginning of the complications.
I think there is no standard way to count the number of arguments, it can be implemented in a number of ways, if that is what you are really asking, which I would have tagged as C
instead of C++
.
How to access the arguments: there are two choices, let us call it the "machine gun" and the "drip-drip-drip" --these are my names--:
#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)...);
}
This builds in the compiler explorer, https://godbolt.org/z/aSx2wv
Upvotes: 3
Reputation: 238421
There is technically one way, which is analogous to how it is possible to get the length of a null terminated string: Use particular argument value to designate the end of the argument list.
However, note that in order to use va_start
, there must be at least one named parameter. In your example you attempt to pass a local variable into va_start
which is not allowed. That macro doesn't take "the number of arguments". It takes "last named argument before variadic parameters start".
That said: I recommend against using C-style variadic functions.
Upvotes: 1
Reputation: 1590
Getting the amount of arguments is not possible in C va_args
. The best you can do is to use a magic value that ends the sequence and a macro to hide it from your user:
#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);
}
As mentioned in the comments, you could alternatively use C++ fold expressions. The above has the advantage of being compatible with C and compiling faster, while the C++ approach gives you type safety.
Upvotes: 3