可以作为固定大小(堆栈)和动态大小(堆)工作的数组封装程序

Array encapsulator that can work as fix-size (stack) AND dynamic-size (heap)

本文关键字:工作 程序 封装 数组 动态 堆栈      更新时间:2023-10-16

昨天,我偶然发现了一个名为Eigen的库,它提供了一个数组类,其签名如下:-

Array<float,Dynamic,1> b;//<--- dynamic = unknown at compile time
Array<float,3,1>       c;//<--- both row(=3) and col(=1) known at compile time

这是Array.h和一个密切相关的类PlainObjectBase.h的源代码。

据我猜测(从挖掘中),如果行和列在编译时都是已知的,它会将内存分配为堆栈变量,方法如下:-

float c[3];

我认为它非常酷,因为它可以避免不必要的堆分配
在某些情况下它非常合适。

问题

创建同时支持fix&1类内的动态大小

它背后的想法是什么
我不是要完整的代码或任何片段,但我不介意。

答案可以忽略所有关于如何实现特征数组的事实。(Eigen只是一个例子。)

我想要一些可靠的想法来改进我自己的阵列封装器,使其像那样酷。

我糟糕的解决方案

  • 为两个场景创建字段(dynamic&fix),但在每个场景中,只使用其中的一部分
  • 然后,垃圾邮件std::enable_if控制动态vs Const,但我认为它是反模式的

他们用部分专业化来完成。基本上,Array类模板将存储的创建委托给另一个类模板,该类模板部分专用于他们命名为Dynamic的某个神奇值。

这里有一个基本的例子:

#include <memory>
constexpr int Dynamic = -1;
template <typename T, int N>
struct Storage
{
Storage() : data{} {}
T data[N];
};
template <typename T>
struct Storage<T, Dynamic>
{
Storage(int count) : data{new T[count]} {}
Storage() = delete;
std::unique_ptr<T[]> data;
};

template <typename T, int N>
struct Array
{
Array() : storage{} {}
Array(int count) : storage{count} {}
Storage<T, N> storage;
};

int main() {
Array<int, 4> a1;
//Array<int, 4> a2(10);  // Error since base Storage template has no constructor taking int.
Array<int, Dynamic> a3(10);
//Array<int, Dynamic> a4{};  // Error since Storage<T, Dynamic> has its default constructor deleted.
}

现场演示

基本上有两个不同的Storage模板,一个将在N == Dynamic时使用,另一个将用于任何其他值。

事实上,如果您查看DenseStorage.h,您会看到与我的示例类似的模式。有更多的专业化来支持多个维度和各种不同对齐的数据类型,但这是相同的概念。