I was wondering if I could have parameter packs consisting of a single, explicitly specified, type. For example, something like this:
#include
void foo(int... args) {}
No you cannot write that.
But you can have the same effect with this approach:
template
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
void foo(Ints... ints)
{
static_assert(is_all_same::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 sink(T && ... ) {} };
template
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 itself:
void foo(initializer_list const & ints)
{
}
Or std::vector 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!