[英]Writing variadic template constructor
最近我问了这个问题,但现在我想扩大它。 我写了以下课程:
template <class T>
class X{
public:
vector<T> v;
template <class T>
X(T n) {
v.push_back(n);
}
template <class T, class... T2>
X(T n, T2... rest) {
v.push_back(n);
X(rest...);
}
};
使用时创建对象
X<int> obj(1, 2, 3); // obj.v containts only 1
Vector仅包含第一个值,但不包含其他值。 我已经检查并看到构造函数被调用了3次,所以我可能正在创建临时对象并用其余参数填充它们的向量。 我该如何解决这个问题?
首先,你的代码不能为我编译。
main.cpp:7:15: error: declaration of ‘class T’
template <class T>
^
main.cpp:3:11: error: shadows template parm ‘class T’
template <class T>
^
我把外面的一个改成了U
template <class U>
class X{
public:
vector<U> v;
template <class T>
X(T n) {
v.push_back(n);
}
template <class T, class... T2>
X(T n, T2... rest) {
v.push_back(n);
X(rest...);
}
};
你是正确的,这导致你在问题细节中给出的问题......
X<int> obj(1, 2, 3); // obj.v containts only 1
这是因为构造函数末尾的语句X(rest...)
不会递归调用构造函数来继续初始化同一个对象; 它会创建一个新的 X
对象,然后将其抛弃。 一旦构造函数的主体开始执行,就不再可能在同一个对象上调用另一个构造函数。 委派必须在ctor-initializer中进行 。 例如,你可以这样做:
template <class T, class... T2>
X(T n, T2... rest): X(rest...) {
v.insert(v.begin(), n);
}
但这很糟糕,因为在向量的开头插入效率不高。
最好采用std::initializer_list<T>
参数。 这就是std::vector
本身所做的。
X(std::initializer_list<U> il): v(il) {}
// ...
X<int> obj {1, 2, 3};
完全同意Brian的回答,但即使正确的方法是另一个(即使用initializer_list),请注意(为了在其他情况下正确地执行此操作),在这种情况下,可变模板递归可以通过注意到empty pack是一个有效的模板参数包,因此最后一次使用空包调用可变参数模板构造函数,这将导致尝试调用默认的ctor,它只能被默认并终止递归。
IOW,以下工作将会更加清洁IMO:
template <class T>
struct X
{
std::vector<T> v;
X() = default; //Terminating recursion
template <class U, class... Ts>
X(U n, Ts... rest) : X(rest...) { .. the recursive work ..}
};
同样,我不是说模板和递归在这里是正确的,我只是指出它们是必要的,有一种更简单的方法来使用它们。
首先不需要递归 -
你可以使用“临时数组”成语并写
template <class... E>
X(E&&... e) {
int temp[] = {(v.push_back(e), 0)...};
}
这种方法的正确(和更复杂)版本如下所示:
template <class... E>
X(E&&... e) {
(void)std::initializer_list<int>{(v.push_back(std::forward<E>(e)), void(), 0)...};
}
请注意,下一版本的C ++可能会有Fold Expressions
(v.push_back(e), ...);
template <class T, class... Rest>
X(T n, Rest... rest) {
add(rest...);
}
//Just another member function
template<class T>
void add(T n) {
v.push_back(n);
}
template<class T, class ... Rest>
void add(T n, Rest... rest) {
v.push_back(n);
add(rest...);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.