如何在(例如)STL 容器中引入聚合初始化支持以正确构造它们?我的意思是:
struct A { int i; char c; };
std::list< A > l; // empty
l.insert(std::memberwise, 1, '2');
// <=> l.insert({1, '2'});
std::memberwise
是一个可能的标签,就像在 STL 中已经存在一样 std::piecewise_construct
, std::allocator_arg
等
理论上可以用这种方式扩展STL容器吗?有没有最好的方法(“STL-way”)来做到这一点?它可能看起来像什么?
问题是关于界面设计和(内部)实现的可能性(不是细节)。
我确定容器使用类似 ::new (static_cast< void * >(pstorage) value_type(std::forward< Args >(args)...);
的东西在内部。我敢肯定,用大括号替换方括号会带来重大变化。因为没有变窄,例如
另外
一般l.insert({1, '2'});
评论中提到的可能导致过度移动value_type
.这一步很可能会被任何现代编译器优化掉,但无论哪种方式都会有过多的大括号。
最佳答案
你应该使用 emplace
式建筑。标准库容器将此类构造转发给 allocator_traits<Alloc>::construct<T>
,这应该是一个可变参数函数。如果Alloc
没有construct
成员函数,然后 allocator_traits::construct
将简单地使用 placement new with ()
初始化语法。
显然,这不允许您通过 emplace
进行聚合初始化.但是,您可以有效地实现 the solution suggested by LWG 2089通过提供您自己的分配器,可能来自 std::allocator
, 它有自己的 construct
方法。你的construct
应该只使用 new(p) T(...)
如果is_constructible<T, ...>::value
是真的。如果不是,则使用 new(p) T{...}
.
在C++17中,这其实不难写:
template< class U, class... Args >
void construct( U* p, Args&&... args )
{
if constexpr(std::is_constructible_v<U, Args...>)
::new((void*)p) U(std::forward<Args>(args)...);
else
::new((void*)p) U{std::forward<Args>(args)...};
}
关于c++ - 如何将聚合支持到 STL 或类似 STL 的库中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41385190/