你想做的事情在 C++ 中是可能的,并不容易,而且你的接口struct
不是struct
样式接口。
就像 a 如何std::vector
获取一块内存并将其重新格式化为非常像数组的东西,然后重载运算符以使其看起来像数组一样,您也可以这样做。
访问您的数据将通过访问者进行。您将在缓冲区中手动构建您的成员。
您可以从成对的“标签”和数据类型列表开始。
struct tag1_t {} tag1;
struct tag2_t {} tag2;
typedef std::tuple< std::pair< tag1_t, int >, std::pair<tag2_t, double> > header_t;
然后,我们将解释为“在标题部分之后,我们有一个数组”的更多类型。我想大幅改进这种语法,但现在重要的部分是建立编译时间列表:
struct arr_t {} arr;
std::tuple< header_t, std::pair< arr_t, std::string > > full_t;
然后,您必须编写一些模板 mojo,N
在运行时计算出您需要存储多大的缓冲区int
,double
然后是 的N
副本std::string
,所有内容都正确对齐。这并不容易。
完成此操作后,您还需要编写构建上述所有内容的代码。如果你想变得花哨,你甚至可以公开一个完美的转发构造函数和构造函数包装器,允许在非默认状态下构造对象。
最后,编写一个接口,根据我注入到上述tuple
s 中的标签找到构造对象的内存偏移量,reinterpret_cast
将原始内存转换为对数据类型的引用,并返回该引用(在 const 和非 const 中)版本)。
对于最后的数组,您将返回一些已重载的临时数据结构,operator[]
它会产生引用。
如果您看一下如何std::vector
将内存块转换为数组,并将其与boost::mpl
标签到数据映射的排列方式相结合,然后手动调整以保持正确对齐,那么每一步都是具有挑战性的,但并非不可能。我在这里使用的杂乱语法也可以改进(在某种程度上)。
最终接口可能是
Foo* my_data = Foo::Create(7);
my_data->get<tag1_t>(); // returns an int
my_data->get<tag2_t>(); // returns a double
my_data->get<arr_t>()[3]; // access to 3rd one
可以通过一些重载来改进:
Foo* my_data = Foo::Create(7);
int x = my_data^tag1; // returns an int
double y = my_data^tag2; // returns a double
std::string z = my_data^arr[3]; // access to 3rd std::string
但是要做到这一点,所涉及的努力将相当大,而且所需的许多事情都非常可怕。
基本上,为了解决你所描述的问题,我必须在 C++ 中手动重建整个 C++/C 结构布局系统,一旦你完成了,在最后注入“任意长度的数组”就不难了. 甚至可以在中间注入任意长度的数组(但这意味着查找该数组之后的结构成员的地址是一个运行时问题:但是,由于我们operator^
允许运行任意代码,并且您的结构可以存储数组的长度,我们能够做到这一点)。
但是,我想不出一种更简单、可移植的方式来完成您在 C++ 中提出的要求,其中存储的数据类型不必是标准布局。