1

例如,

template <typename T>
struct node {
  T data;
  node* pnext;
};

template <typename T, typename... Us>
void func(Us&&... args) {
  // Initialize a node<T> with data initialized from args...
}

我能想到的方法及其局限性。

  1. node<T> v{ T(forward<Us>(args)...) }. 这涉及复制初始化,如果T不可复制且不可移动,例如原子类型,则复制初始化将无法工作。

  2. node<T> v{ {forward<Us>(args)...} }. 这涉及复制列表初始化,如果所选构造函数是显式的,则该初始化将无法工作。例如,node<unique_ptr<int>> n{ {new int()} }不起作用。

我想如果我能以某种方式直接初始化(例如,直接列表初始化)聚合成员,问题就解决了。然而,除了编写用户提供的构造函数、制作非聚合类型之外,我没有发现这是怎么可能的node,这太过分了,我不愿意这样做。任何的想法?

4

1 回答 1

2

C++14 没有有效的解决这个困境的办法。好吧,不是在仍然使用聚合初始化的时候。如果你给出node<T>一个可变参数构造函数,那么它可以直接将参数转发给成员初始化器:

template <typename T>
struct node {
  T data;
  node* pnext;

  template<typename ...Args>
  node(Args ...&&args) : data(std::forward<Args>(args)...) {}
};

从而允许您调用node<T> v( T(forward<Us>(args)...) ). 当然,它不再是聚合。

C++17 的保证省略规则允许node<T> v{ T(forward<Us>(args)...) }不引起复制或移动。

于 2018-02-25T04:41:34.173 回答