我有一个基本类型B和它的子类型列表,如B1,B2,它们是从B派生的。我想开发一个函数来制作一个带有新B1,新B2和左右元素的指针vetor,像
template<class BaseType, class... SubTypes>
vector<unique_ptr<BaseType>> makePtrVector()
{
vector<unique_ptr<BaseType>> v;
v.emplace_back(new SubTypes)...; // error, SubTypes has to be expanded
return v;
}
我尝试了上面的代码却失败了。我不清楚参数包的扩展。任何纠正它的方法或它只是一个编译器错误?
答案 0 :(得分:2)
您只能在某些上下文中执行参数包扩展。完整的陈述级别不是其中之一。
std::vector::emplace_back
返回void
,因此我们可以执行此操作:
struct empty {};
template<class BaseType, class... SubTypes>
vector<unique_ptr<BaseType>> makePtrVector() {
vector<unique_ptr<BaseType>> v;
empty unused[]= {(v.emplace_back(new SubTypes), empty{})..., empty{}}; // error
return v;
}
我们在其中创建empty
类型的初始化列表,作为其构造的副作用,调用您喜欢的代码。 (int
也很受欢迎)。
另一种解决方法是将其转移到辅助函数中。但是,这不适用于每个编译器:
template<typename...Fs>
void do_in_order( Fs&&... fs ) {
empty unused[]= { (void( std::forward<Fs>(fs) ), empty{})..., empty{} };
}
然后在你的代码中:
template<class BaseType, class... SubTypes>
vector<unique_ptr<BaseType>> makePtrVector() {
vector<unique_ptr<BaseType>> v;
do_in_order( [&]{ v.emplace_back(new SubTypes); }... );
return v;
}
看起来不那么钝的不是吗?缺点是一些主要的编译器不喜欢lambda中的不完整参数包,只有在lambda的紧密结束后才会扩展。