Reputation: 7388
In C++ I can define a function with a variable number of arguments like this:
void a(int a...) {
std::cout << a << std::endl;
}
And call it like this:
a(100, 200, 300);
However, apparently I can only access the first argument: The output of the call is 100
.
How do I access the other arguments with this notation?
Upvotes: 0
Views: 229
Reputation: 18946
Sample code using your function a
:
#include <iostream>
#include <cstdarg>
void a(int a...)
{
va_list args;
va_start(args, a);
int b = va_arg(args, int);
int c = va_arg(args, int);
std::cout << a << ", " << b << ", " << c << std::endl;
}
int main()
{
a(100, 200, 300);
return 0;
}
The variable argument syntax does not know the number or type of the parameters. Therefore something in the parameter list must indicate the number and possibly the type of the parameters. There are several methods that are typically used to determine the number of parameters:
In this example, I've simply assumed there are three parameters. Calling a
with more or less parameters will cause undefined behavior (read, random results, to a crash).
Upvotes: 0
Reputation: 218098
A solution which enforces the type int
.
But with a usage a little different
#include <initializer_list>
#include <iostream>
// Or you may use std::vector
void print(const std::initializer_list<int>& a) {
for (auto elem : a) {
std::cout << elem << std::endl;
}
}
int main(int argc, char *argv[])
{
print({1, 2, 3}); // extra braces.
return 0;
}
Upvotes: 0
Reputation: 4109
Another variadic solution:
template<typename T, typename... Vs>
void print(T&& t, Vs&&... vs) {
std::cout << std::forward<T>(t) << std::endl;
int sink[] { (std::cout << " " << std::forward<Vs>(vs) << std::endl, 0)... };
(void)sink; // silence "unused variable" warning
}
Which has the benefit of not requiring helpers. We use pack expansion to forward each argument one at a time to cout. For syntax reasons, I leverage the comma operator so that the expression (cout..stuff.., 0) resolves to an integer, which we then discard into an array; this lets us use the pack expansion operator around our complex statement.
Upvotes: 0
Reputation: 275800
Your syntax is ... unfortunate, and refers to a C-style vararg function.
In C++11 you should prefer variardic template
s. The easiest approach is something like this:
First, some helper code:
#include <utility>
template<typename Lambda>
void for_each_arg( Lambda&& unused ) {}
template<typename Lambda, typename Arg1, typename... Args>
void for_each_arg( Lambda&& closure, Arg1&& arg1, Args&&... args ) {
closure( std::forward<Arg1>(arg1) );
for_each_arg( std::forward<Lambda>(closure), std::forward<Args>(args)... );
}
now, we use it:
#include <iostream>
template<typename... Args>
void foo( Args&&... args ) {
for_each_arg( [](int x){
std::cout << x << "\n";
}, std::forward<Args>(args)... );
}
int main() {
foo( 1, 2, 3 );
}
and we can access each argument, and ensure that they convert to int
. Note that the conversion to int
is deferred until call of the body of for_each_arg
.
Upvotes: 4
Reputation: 153995
If you use a var args interface you need to be able to tell from the named parameters how many arguments where provided in total. For example, the <stdio.h>
function do that by having the format string be the last named argument followed by as many arguments as specified in the argument list. To access the arguments you need to use the various va_...
functions and types.
You are much better off using variadic templates:
template <typename... T>
void f(T... a) {
// just expand the parameter pack over here
}
Upvotes: 1