简体   繁体   English

在不使用动态分配的情况下,C++14 替代 C99 复合文字的方法是什么?

[英]What is the C++14 alternative to C99 compound literals, without using dynamic allocation?

I'm developing an Embedded System with an ARM processor with an MPU, using C++14, and I want to keep the number of dynamic allocations down, also during initialization, as I prefer to know the exact amount of memory used at link time.我正在开发一个带有 MPU 的 ARM 处理器的嵌入式系统,使用 C++14,我想保持动态分配的数量,也在初始化期间,因为我更喜欢知道链接中使用的确切内存量时间。

In C99, you can allocate memory on the stack or global scope using compound literals, see this nonsense code, that allocates a struct within a struct at compile-time:在 C99 中,您可以使用复合文字在堆栈或全局范围上分配内存,请参阅此废话代码,该代码在编译时在结构中分配结构:

struct Foo {
    struct Foo* next;
};
struct Foo *bar = {
    &(struct Foo){
        &(struct Foo){ NULL }
    }
};

It's not possible to use any GCC or Clang extensions to solve this problem, only pure C++14 code.不可能使用任何 GCC 或 Clang 扩展来解决这个问题,只能使用纯 C++14 代码。

The only simple method, that I've found, to mimic this behavior, is to use lambda functions.我发现模仿这种行为的唯一简单方法是使用 lambda 函数。 However, this solution is not reentrant.但是,此解决方案不可重入。

struct Foo* bar = [](){
    static struct Foo bar = {
        static struct Foo bar = { nullptr };
        return &bar;
    }();
    return &bar;
}();

The lambda solution would work in my case, and I could use macros to make it more comfortable to use, but it's not a solution if I want to put the data structure on the stack. lambda 解决方案适用于我的情况,我可以使用宏使其使用起来更舒适,但如果我想将数据结构放在堆栈上,这不是一个解决方案。

What is the best C++ approach to solving this problem (without using dynamic allocation)?解决此问题的最佳 C++ 方法是什么(不使用动态分配)?

The current problem I'm trying to solve is a tree of derived classes, and I would like to assign it at compile-time.我正在尝试解决的当前问题是派生类树,我想在编译时分配它。

What I'm trying to achieve in imagined C++ code:我试图在想象的 C++ 代码中实现的目标:

RootClass* b = &(DerivedClass1){ &(DerivedClass2){10},
                                 &(DerivedClass2){20},
                                 &(DerivedClass1){ &(DerivedClass0){} }
                               };

What I'm trying to achieve in imagined C++ code:我试图在想象的 C++ 代码中实现的目标:

Well that's never going to work.嗯,这永远不会奏效。 There's no requirement that any of those derived classes are the same size as the base class, so it would be impossible to do pointer arithmetic on the base class (even if C++ allowed pointer arithmetic on base class pointers to arrays where the element type is a derived class. Which it does not ).不要求这些派生类中的任何一个与基类的大小相同,因此不可能对基类进行指针算术(即使 C++ 允许对指向元素类型为数组的基类指针进行指针算术)派生类。它没有)。

If you were dealing with a single type T , then you could just do this:如果您正在处理单个类型T ,那么您可以这样做:

T ts[] = {<initializers>};

And you could use ts as you see fit.您可以根据需要使用ts But this only works for proper arrays.但这仅适用于正确的数组。

Now, if you want to do your derived class thing, you can always use a tuple as the container of the derived class elements, and then build an array of pointers to the base class elements so that you could iterate from one to the other.现在,如果你想做你的派生类的事情,你总是可以使用一个tuple作为派生类元素的容器,然后构建一个指向基类元素的指针数组,这样你就可以从一个元素到另一个元素进行迭代。 C++14 makes this a bit cumbersome, as it requires that you list the type in the tuple type itself, but C++17's class template argument deduction makes it more digestible: C++14 使这有点麻烦,因为它要求您在tuple类型本身中列出类型,但 C++17 的类模板参数推导使其更易于理解:

auto tpl = tuple(DerivedClass2{10}, DerivedClass2{20}, DerivedClass1{DerivedClass0{}});

The C++14 version just repeats the types. C++14 版本只是重复了类型。

Building the array requires some template metaprogramming techniques:构建数组需要一些模板元编程技术:

template<typename BC, typename Tpl, std::size_t ...ixs>
auto GetBaseClassArrayHelper(Tpl &tpl, std::index_sequence<ixs...>)
{
    return std::array<BC*, std::tuple_size<Tpl>::value>{static_cast<BC*>(std::get<ixs>(tpl))...};
}

template<typename BC, typename Tpl>
std::array<BC*, std::tuple_size<Tpl>::value> GetBaseClassArray(Tpl &tpl)
{
    return GetBaseClassArrayHelper<BC>(tpl, std::make_index_sequence<std::tuple_size<Tpl>::value>{});
}

Now, this doesn't let you take a BaseClass* and ++ it into a different BaseClass* .现在,这不会让您将BaseClass*++带入不同的BaseClass* You'd need to have a pointer into the array of pointers, a BaseClass** in order to do that.你需要有一个指向指针数组的指针,一个BaseClass**才能做到这一点。

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

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