实现任意类型擦除的小缓冲区优化的简单方法(如 std::function 中。)

问题描述 投票:0回答:3

我经常使用类型擦除技术。 它通常看起来像这样:

class YetAnotherTypeErasure
{
public:
   // interface redirected to pImpl
private:
   // Adapting function
   template ...
   friend YetAnotherTypeErasure make_YetAnotherTypeErasure (...);

   class Interface {...};

   template <typename Adaptee>
   class Concrete final : public Interface { 
     // redirecting Interface to Adaptee
   };

   std::unique_ptr<Interface> pImpl_; // always on the heap
};

std::function
做了类似的事情,但它有一个小的缓冲区优化,所以如果
Concrete<Adaptee>
小于smth并且没有抛出移动操作,它将被存储在其中。是否有一些通用的库解决方案可以相当容易地做到这一点?为了强制只在编译时存储小缓冲区?也许已经提出了一些标准化建议?

c++ c++11
3个回答
3
投票

我对标准或任何提案所要求的小缓冲区优化一无所知,尽管它经常被允许或鼓励。

请注意,此类类型的一些(有条件的)非抛出要求实际上需要在实践中进行优化,因为替代方案(例如来自紧急缓冲区的非抛出分配)在这里似乎很疯狂。

另一方面,您可以基于标准库(例如

std::aligned_storage

)从头开始制作自己的解决方案。从用户的角度来看,这可能仍然很冗长,但并不太难。

实际上我几年前就实现了(当时没有提出)

any这样的优化

一些相关的实用程序。最近,libstdc++ 的 std::experimental::any 实现使用了几乎与此完全相同的技术(但是,
__
前缀的内部名称对于普通库用户来说肯定不好)。
我的实现现在使用

一些常见的助手

来处理存储。这些助手确实可以轻松实现类型擦除存储策略(至少适合类似于any的东西)。但我仍然对更通用的高级解决方案感兴趣,以简化界面重定向。

还有一个

function实现

直接基于上面的
any实现。它们支持仅移动类型和合理的分配器接口,而
std
则不支持。在某些情况下,由于底层
function
对象的(部分无操作)默认初始化,
std::function
实现比 libstdc++ 中的
any
具有更好的性能。
    


2
投票

通过小型库支持来帮助保持 const 的正确性, 代码减少到 20 行:

https://gcc.godbolt.org/z/GtewFI


1
投票
wg21.link/p0201

基本上它就像 std::any 但所有类型都必须继承相同的接口。 这是半规则的,他们决定放弃平等。

这有一些开销:类本身有一个 vptr,多态值中有一个单独的调度机制。它还有一个类似指针的接口,而不是像这样的值。

但是,考虑到与编写自己的 type_erased 适配器相比使用它是多么容易,我想说对于大多数用例来说已经足够好了。

© www.soinside.com 2019 - 2024. All rights reserved.