我想知道我是否可以拥有由单个明确指定的类型组成的参数包。例如,像这样:
#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);
}
我遇到的问题是 foo()
的定义。使用 OS X clang++ 版本 5 (llvm 3.3svn) 我收到错误 error: type 'int' of function parameter pack does not contain any unexpanded parameter packs
。
当然,我可以通过将 foo()
更改为函数模板来编译它:
template<typename... Args>
void 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_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' :)
}
所以这很整洁。但问题仍然存在,这有必要吗?真的没有办法定义一个接受特定类型参数包的非模板函数吗?像这样:
void foo(int... args) { }
原文由 stack_lexi 发布,翻译遵循 CC BY-SA 4.0 许可协议
不,你不能那样写。
但是您可以使用这种方法获得相同的效果:
使用这种方法,您可以根据需要传递所有
int
。如果传递给foo
的任何参数不是int
或可转换为int
,上面的代码将导致编译错误,因为它会是这种情况int ...args
如果允许就接近。您也可以使用
static_assert
来确保所有Ints
确实是int
如果您想要这种行为:现在你要实现
is_all_same
元函数,这并不难实现。好的,这是基本的想法。您可以使用可变参数模板并借助一些实用元函数和辅助函数编写更复杂的代码。
对于可以使用可变参数进行的大量工作,您甚至不需要存储在
args[]
数组中,例如,如果您想将参数打印到std::ostream
,那么您可以只需这样做:在这里,您创建一个类型为
sink
的临时对象,以便使用列表初始化语法解压缩模板参数。最后你可以使用
std::initializer_list<int>
本身:或者
std::vector<int>
以防您需要在foo()
内部进行类似矢量的行为。如果您使用其中任何一个,则在调用函数时必须使用{}
:这可能并不理想,但我认为随着 C++11 的出现,您会经常看到这样的代码!