I was wondering if I could have parameter packs consisting of a single, explicitly specified, type. For example, something like this:
#include <iostream>
using namespace std;
void show() { }
template<typename First, typename... Rest>
void show(First f, Rest... rest)
{
cout << f << endl;
show(rest...);
}
void foo(int f, int... args) // error
{
show(f, args...);
}
int main()
{
foo(1, 2, 3);
}
The problem I'm having is with the definition of foo()
. With OS X clang++ version 5 (llvm 3.3svn) I get the error error: type 'int' of function parameter pack does not contain any unexpanded parameter packs
.
Of course, I can get it to compile by changing to foo()
into a function template:
template<typename... Args>
void foo(int f, Args... args)
{
show(f, args...);
}
However now foo()
will accept int
for the first parameter, and anything output streamable for the rest. For example:
struct x { };
ostream& operator<<(ostream& o, x)
{
o << "x";
return o;
}
int main()
{
foo(1, 2, x(), 3); // compiles :(
}
Now, I've seen the accepted solution here which suggests using type traits and std::enable_if
, but that's cumbersome. They also suggested using std::array
but I think a simple std::initializer_list
works just fine and looks cleaner, like so:
void foo_impl(initializer_list<int> ints)
{
for(int i: ints)
cout << i << endl;
}
template<typename... Args>
void foo(int f, Args... args)
{
foo_impl({f, args...});
}
struct x { };
ostream& operator<<(ostream& o, x)
{
o << "x";
return o;
}
int main()
{
foo(1, 2, 3);
foo(1, 2, x(), 3); // no longer compiles
// we also get an error saying no known conversion from 'x' to 'int' :)
}
So that's neat. But the question remains, is this necessary? Is there really not a way to define a non-template function which accepts a parameter pack of specific type? Like this:
void foo(int... args) { }
See Question&Answers more detail:os