繁体   English   中英

编写可变参数模板构造函数

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM