在通用模板代码中初始化聚合成员
Initialize aggregate member in generic template code
例如,
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...
}
我能想到的方法及其局限性。
node<T> v{ T(forward<Us>(args)...) }
。这涉及copy-initialization which fails to work if T
is non-copyable and non-movable, e.g., an atomic类型。
node<T> v{ {forward<Us>(args)...} }
。这涉及 copy-list-initialization 如果选择的构造函数是显式的,它将无法工作。例如,node<unique_ptr<int>> n{ {new int()} }
不起作用。
如果我能以某种方式直接初始化(例如,直接列表初始化)聚合成员,我想问题就解决了。然而,除了编写用户提供的构造函数,使 node
成为非聚合类型之外,我没有发现这有什么可能,这太过分了,我不愿意这样做。有什么想法吗?
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)...) }
不引发复制或移动。
例如,
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...
}
我能想到的方法及其局限性。
node<T> v{ T(forward<Us>(args)...) }
。这涉及copy-initialization which fails to work ifT
is non-copyable and non-movable, e.g., an atomic类型。node<T> v{ {forward<Us>(args)...} }
。这涉及 copy-list-initialization 如果选择的构造函数是显式的,它将无法工作。例如,node<unique_ptr<int>> n{ {new int()} }
不起作用。
如果我能以某种方式直接初始化(例如,直接列表初始化)聚合成员,我想问题就解决了。然而,除了编写用户提供的构造函数,使 node
成为非聚合类型之外,我没有发现这有什么可能,这太过分了,我不愿意这样做。有什么想法吗?
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)...) }
不引发复制或移动。