简体   繁体   English

数组模板兼容性的好模式是什么?

[英]What is a good pattern for array template compatibility?

I would like to create objects having a variable-length array of elements, and have them be compatible in a base/derived-class sense.我想创建具有可变长度元素数组的对象,并让它们在基类/派生类意义上兼容。 In C, one could put an indeterminate array at the end of a struct and then just malloc the object to contain the full array:在 C 中,可以在struct的末尾放置一个不确定的数组,然后只需 malloc 对象以包含完整的数组:

struct foo {
    int n;
    double x[];
} ;

struct foo *foo1 = (foo *)malloc( sizeof( foo ) + sizeof( double[4] ) );
struct foo *foo2 = (foo *)malloc( sizeof( foo ) + sizeof( double[100] ) );

In c++, it seems like you could do:在 c++ 中,您似乎可以这样做:

template <unsigned I>
class foo {
public:
    int n;
    double x[I];
} ;

but:但:

auto foo1 = new foo<4>( );
auto foo2 = new foo<100>( );

if (foo1 == foo2) cerr << "incompatible pointers";

You can do it with a common base class, but is that necessary?你可以用一个通用的基类来做到这一点,但这有必要吗? I just want to use foo1 and foo2 , where each object knows the length of its array.我只想使用foo1foo2 ,其中每个对象都知道其数组的长度。


My application is for an ESP32 microcontroller running FreeRTOS.我的应用程序适用于运行 FreeRTOS 的 ESP32 微控制器。 It has limited, non-virtual RAM and a slightly complicated allocation system because of differing capabilities of various chunks of memory (some is slower, some can't contain executable code, some can't be accessed by DMA, etc.) So allocating multiple chunks for pieces of an object (for example, by using std::vector for the array of double at the end) becomes complicated.它具有有限的非虚拟 RAM 和稍微复杂的分配系统,因为各种内存块的功能不同(有些速度较慢,有些不能包含可执行代码,有些不能通过 DMA 访问等)所以分配对象的多个块(例如,通过在末尾使用std::vector作为double数组)变得复杂。

I know the length of the double array at object construction time, but I would like the header and the array to be in a single allocated block of memory (so it can have the characteristics I need for it to have later).我在对象构造时知道double精度数组的长度,但我希望标头和数组位于单个分配的内存块中(因此它可以具有我以后需要的特性)。

The C-style way of doing it would be fine, but it would be nice to have C++ features like iteration over the array (for various objects, which will each have different numbers of double s). C 风格的做法会很好,但是如果有 C++ 的特性,比如在数组上迭代(对于各种对象,每个对象都有不同数量的double ),那就太好了。 Plus, a native C++ solution would allow me to have objects in the x[] array, instead of fooling around with placement new in raw allocated memory.另外,本机 C++ 解决方案将允许我在x[]数组中拥有对象,而不是在原始分配的内存中放置new So, for example:因此,例如:

auto a[] = { new foo<5>( ), new foo<10>( ), new foo<15>( ) };

for (auto i : a)
    for (auto j : i.x)
        cout << log10( j );    // prints 40 logs of doubles

(I expect that's got C++ syntax errors, but hopefully it communicates the idea. I can figure out the syntax for that, if I could get all the foo s into a common container.) (我希望这有 C++ 语法错误,但希望它能传达这个想法。如果我可以将所有foo放入一个公共容器中,我可以弄清楚它的语法。)

As a low-level C++ developer, I understand exactly what you need, and sadly, there is no replacement for flexible array members in standard C++, with or without templates.作为一名低级 C++ 开发人员,我完全了解您的需求,遗憾的是,无论有没有模板,标准 C++ 中的灵活数组成员都无法替代。 You have to keep using flexible array members via compiler extensions.您必须通过编译器扩展继续使用灵活的数组成员。

They are not included in the language since in their current form, they are essentially a hack.它们不包含在语言中,因为以它们当前的形式,它们本质上是一种 hack。 They don't do well with inheritance or composition.它们在继承或组合方面做得不好。

The problem with templates is that, the flexible array version has a common type of arrays of all sizes.模板的问题在于,灵活的数组版本具有各种大小的通用数组类型。 That means you can place them in arrays, have non-template functions take them as parameters etc:这意味着您可以将它们放在数组中,让非模板函数将它们作为参数等:

foo* make_foo(int n);

foo* foos[] = { make_foo(1); make_foo(2); make_foo(3); }; // ok

void take_foo(foo*);

With the template version, types foo<1> and foo<2> are completely unrelated, so you cannot put them in arrays or have non-template functions that take them:在模板版本中,类型foo<1>foo<2>完全不相关,因此您不能将它们放在数组中或使用非模板函数来获取它们:

template <int N>
foo<N>* make_foo();

auto foos[] = { make_foo<1>(), make_foo<2>(), make_foo<3>() }; // ill-formed

template <int N>
void take_foo(foo<N>*);

std::array won't help in this discussion, and inheriting from one will still have the problem of having unrelated types. std::array在这个讨论中没有帮助,从一个继承仍然会有不相关类型的问题。

However, since this is still C++ (albeit non-standard), you can at least have some additional niceties:然而,由于这仍然是 C++(尽管是非标准的),你至少可以有一些额外的细节:

template <class T>
struct flex_array {
  int n;
  T data[];

  T* begin() { return &data[0]; }
  T* end() { return begin() + n; }
};


void iterate(flex_array<double>& f) {
    for (double j : f) {
        cout << log10(j); // print however many doubles are in f
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM