【问题标题】:How to support an aggregates into the STL or STL-like library如何支持聚合到 STL 或类似 STL 的库中
【发布时间】:2016-12-29 18:22:07
【问题描述】:

如何引入聚合初始化支持以在(例如)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_constructstd::allocator_arg等。

理论上可以以这种方式扩展 STL 容器吗?有没有最好的方法(“STL-way”)来做到这一点?它可能是什么样子?

问题是关于界面设计和(内部)实现的可能性(不是细节)。

我确定容器在内部使用 ::new (static_cast&lt; void * &gt;(pstorage) value_type(std::forward&lt; Args &gt;(args)...); 之类的东西。我敢肯定,用大括号替换括号会带来重大变化。因为不收窄,例如

另外

一般在cmets中提到的l.insert({1, '2'});会导致value_type的过度移动。这一步很可能会被任何现代编译器优化,但无论哪种方式都有过多的大括号。

【问题讨论】:

  • 在您的具体情况下,l.insert({1, '2'}); 在 C++11 中工作。
  • @Chad 是的,AFAIK,但 l.emplace{,_back}(1, '2'); - 不是。
  • @Orient 您可能需要考虑为初始化 i 和 c 的结构添加一个构造函数。据我所知,对于“就地”容器函数来就地构造对象,您需要这个。如果您通过聚合初始化执行emplaceemplace_back,它实际上会创建一个对象,然后将其复制到结构中。
  • @RyanP 对于通用代码,这是不可能的。没有std::is_aggregate 来检测聚合以将它们包装到aggregate wrapper 中。

标签: c++ stl containers aggregate c++17


【解决方案1】:

您应该使用emplace 样式的构造。标准库容器将这样的构造转发给allocator_traits&lt;Alloc&gt;::construct&lt;T&gt;,预计这是一个可变参数函数。如果Alloc 没有construct 成员函数,那么allocator_traits::construct 将简单地使用带有() 初始化语法的placement new。

显然这不允许您通过emplace 进行聚合初始化。但是,您可以通过提供自己的分配器来有效地实现the solution suggested by LWG 2089,它可能派生自std::allocator,它有自己的construct 方法。如果is_constructible&lt;T, ...&gt;::value 为真,您的construct 应该只使用new(p) T(...)。如果不是,则使用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)...};
}

【讨论】:

  • 真的我不需要可怜的std::initializer_list(因为它不能移动),所以这个解决方案对我来说似乎很完美。谢谢。
  • 是否有意 operator new 不是全局的,operator new 应用于非void 指针?将operator new 重载到Allocator::construct 中是否完全正确?
  • Notes here: the code that wants to ensure that the true placement new is called (e.g. std::allocator::construct), must use ::new and also cast the pointer to void.
  • This 还说明了应该将哪一个用于成员函数模板construct
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-11-12
  • 1970-01-01
  • 2010-09-14
  • 1970-01-01
  • 2012-11-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多