我想知道我是否可以使用由明确指定的单一类型组成的参数包.例如,像这样:
#includeusing namespace std; void show() { } template 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); }
我遇到的问题是定义foo()
.使用OS X clang ++版本5(llvm 3.3svn)我收到错误error: type 'int' of function parameter pack does not contain any unexpanded parameter packs
.
当然,我可以通过更改foo()
为函数模板来编译它:
templatevoid foo(int f, Args... args) { show(f, args...); }
但是现在foo()
将接受int
第一个参数,其余的任何输出都可以流式传输.例如:
struct x { }; ostream& operator<<(ostream& o, x) { o << "x"; return o; } int main() { foo(1, 2, x(), 3); // compiles :( }
现在,我已经看到了这里接受的解决方案,建议使用类型特征std::enable_if
,但这很麻烦.他们还建议使用,std::array
但我认为一个简单的std::initializer_list
工作很好,看起来更干净,像这样:
void foo_impl(initializer_listints) { for(int i: ints) cout << i << endl; } template 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' :) }
这很整洁.但问题仍然存在,这是必要的吗?真的没有办法定义一个接受特定类型参数包的非模板函数吗?像这样:
void foo(int... args) { }
Nawaz.. 22
void foo(int... args) {}
不,你不能写那个.
但是你可以用这种方法产生同样的效果:
templatevoid foo(Ints... ints) { int args[] { ints... }; //unpack ints here //use args }
使用这种方法,您可以int
根据需要传递所有内容.如果传递给的任何参数foo
不是int
或者不能转换为int
,则上面的代码将导致编译错误,因为int ...args
如果允许则会出现方法.
您还可以使用static_assert
以确保所有内容Ints
确实int
如果您想要这种行为:
templatevoid foo(Ints... ints) { static_assert(is_all_same ::value, "Arguments must be int."); int args[] { ints... }; //unpack ints here //use args }
现在你要实现is_all_same
不易实现的元函数.
好吧,这是基本的想法.您可以使用可变参数模板编写更复杂的代码,并借助一些实用程序元函数和辅助函数.
对于你可以使用可变参数进行的大量工作,你甚至不需要存储在args[]
数组中,例如,如果你想打印参数std::ostream
,那么你可以这样做:
struct sink { templatesink(T && ... ) {} }; template void foo(Ints... ints) { //some code sink { (std::cout << ints)... }; }
在这里,您可以创建一个类型的临时对象,sink
以便使用list-initialization语法解压缩模板参数.
最后你可以std::initializer_list
自己使用:
void foo(initializer_listconst & ints) { }
或者std::vector
如果您需要内部的矢量行为foo()
.如果您使用其中任何一个,则必须{}
在调用函数时使用:
f({1,2,3});
这可能不太理想,但我认为随着C++ 11的出现,你会经常看到这样的代码!
void foo(int... args) {}
不,你不能写那个.
但是你可以用这种方法产生同样的效果:
template<typename ...Ints> void foo(Ints... ints) { int args[] { ints... }; //unpack ints here //use args }
使用这种方法,您可以int
根据需要传递所有内容.如果传递给的任何参数foo
不是int
或者不能转换为int
,则上面的代码将导致编译错误,因为int ...args
如果允许则会出现方法.
您还可以使用static_assert
以确保所有内容Ints
确实int
如果您想要这种行为:
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 }
现在你要实现is_all_same
不易实现的元函数.
好吧,这是基本的想法.您可以使用可变参数模板编写更复杂的代码,并借助一些实用程序元函数和辅助函数.
对于你可以使用可变参数进行的大量工作,你甚至不需要存储在args[]
数组中,例如,如果你想打印参数std::ostream
,那么你可以这样做:
struct sink { template<typename ...T> sink(T && ... ) {} }; template<typename ...Ints> void foo(Ints... ints) { //some code sink { (std::cout << ints)... }; }
在这里,您可以创建一个类型的临时对象,sink
以便使用list-initialization语法解压缩模板参数.
最后你可以std::initializer_list<int>
自己使用:
void foo(initializer_list<int> const & ints) { }
或者std::vector<int>
如果您需要内部的矢量行为foo()
.如果您使用其中任何一个,则必须{}
在调用函数时使用:
f({1,2,3});
这可能不太理想,但我认为随着C++ 11的出现,你会经常看到这样的代码!