void foo(int... args) {}
No you cannot write that.
But you can have the same effect with this approach:
template<typename ...Ints>
void foo(Ints... ints)
{
int args[] { ints... }; //unpack ints here
//use args
}
With this approach, you can pass all int
if you want. If any argument passed to foo
is not int
or convertible to int
, the above code will result in compilation error, as it would be the case with int ...args
approach if it were allowed.
You could also use static_assert
to ensure all Ints
are indeed int
if you want that behaviour:
template<typename ...Ints>
void foo(Ints... ints)
{
static_assert(is_all_same<int, Ints...>::value, "Arguments must be int.");
int args[] { ints... }; //unpack ints here
//use args
}
Now you’ve to implement is_all_same
meta-function which is not difficult to implement.
Alright, this is the basic idea. You can write more sophisticated code with variadic templates and with the help of some utility meta-functions and helper functions.
For lots of work that you can do with variadic arguments, you don’t even need to store in args[]
array, e.g if you want to print the arguments to std::ostream
, then you could just do it as:
struct sink { template<typename ...T> sink(T && ... ) {} };
template<typename ...Ints>
void foo(Ints... ints)
{
//some code
sink { (std::cout << ints)... };
}
Here you create a temporary object of type sink
so that you use unpack the template arguments using list-initialization syntax.
Last you could just use std::initializer_list<int>
itself:
void foo(initializer_list<int> const & ints)
{
}
Or std::vector<int>
in case if you need vector-like behavior inside foo()
. If you use any of these, you have to use {}
when calling the function as:
f({1,2,3});
That may not be ideal but I think with the advent of C++11 you will see such code very frequently!