C++11 中不同类型的对象的 std::array 的替代方案

Alternatives to std::array for objects of different types in C++11

本文关键字:array 方案 对象 同类型 C++11 std      更新时间:2023-10-16

我正在寻找有关如何组织和访问数据的更好解决方案。 我的数据是一组结构(在下面的示例中_array_10_array_20(,其中包含不同大小的std::array(请参阅下面的my_data(。 理想情况下,我想访问它,因为它是具有不同长度的结构数组,但这是不允许的,因为不同的长度是不同的类型。 我在下面的解决方案有效,但我发现它非常丑陋(特别是void *数组(。

问题 1.关于如何拥有更安全、更高效/便携或至少不那么丑陋的解决方案的任何想法?
问题 2.没有模板的建议解决方案是否可移植?它依赖于长度存储在其余数据之前的事实,因为将指针转换为长度错误的对象会弄乱对第一个可变长度字段之后的所有字段的访问。

我的局限性包括:

  • C++11
  • 标准库
  • 没有std::vector
  • 内存使用使我无法简单地分配具有最大可能长度的my_data数组
  • 大部分数据(_array_10_array_20等(将被放置在专门为它保留的内存区域中

使用 data_view 和模板需要了解构建时数组的长度。如果我们能避免它,那就太好了。

  • 问题经过编辑,包括纪尧姆·拉西科特提出的解决方案
#include <iostream>
#include <array>
std::array<void *, 2> _ptrs;
template <int length>
struct my_data
{
int                     array_length;
std::array<int, length> something;
std::array<int, length> data;
my_data()
{
array_length = length;
}
};

struct my_data_view
{
int         array_length;
const int * something;
const int * data;
template <int length>
my_data_view(my_data<length> const & data_in) :
array_length(length),
something(data_in.something.data()),
data(data_in.data.data())
{}
};
template <int length>
void
print_element(int array_idx, int element)
{
my_data<length> * ptr = reinterpret_cast<my_data<length> *>(_ptrs[array_idx]);
std::cout << "array " << length << ", data[" << element << "] = " << ptr->data[element] << ".n";
}
void
print_element(int array_idx, int element)
{
my_data<1> * ptr    = reinterpret_cast<my_data<1> *>(_ptrs[array_idx]);
int          length = ptr->array_length;
int data_to_print = 0;
switch (length)
{
case 10:
{
data_to_print = reinterpret_cast<my_data<10> *>(_ptrs[array_idx])->data[element];
break;
}
case 20:
{
data_to_print = reinterpret_cast<my_data<20> *>(_ptrs[array_idx])->data[element];
break;
}
}
std::cout << "array " << length << ", data[" << element << "] = " << data_to_print << ".n";
}
void
print_element(my_data_view view, int element)
{
int length        = view.array_length;
int data_to_print = view.data[element];
std::cout << "array " << length << ", data[" << element << "] = " << data_to_print << ".n";
}
int
main()
{
my_data<10> _array_10;
my_data<20> _array_20;
_ptrs[0] = static_cast<void *>(&_array_10);
_ptrs[1] = static_cast<void *>(&_array_20);
_array_10.data[5] = 11;
_array_20.data[5] = 22;
std::cout << "using templaten";
print_element<10>(0, 5);
print_element<20>(1, 5);
std::cout << "nwithout templaten";
print_element(0, 5);
print_element(1, 5);
std::cout << "nusing data_viewn";
print_element(my_data_view(_array_10), 5);
print_element(my_data_view(_array_20), 5);
}

您可以创建一个不分配以下内容的动态视图类:

struct my_data_view
{
int array_length;
std::span<int> something;
std::span<int> data;
template<int length>
my_data_view(my_data<length> const& data) : 
array_length{length}, something{data.something}, data{data.data}
{}
};

跨度只是一个指针和一个大小。如果您无权访问std::span(从 C++20 开始(,您可以简单地将这些成员替换为int*并使用array_length作为大小。

my_data_view类型是这样使用的:

void
print_element(my_data_view view, int element)
{
int length = view.array_length;
int data_to_print = view.data[element];
std::cout << "array " << length << ", data[" << element << "] = " << data_to_print << ".n";
}

这是适用于std::span和简单int*的代码。