在 C++ 中,如何在不使用 new 且不单独声明各个元素的情况下创建 `std::initializer_list` ?

2024-03-13

在 C++ 中,您可以在文件范围内声明一个数组:

static foo a[] = { foo(), foo(), foo() };

各个 foo 对象具有静态存储(即它们不在运行时分配)。

如果我有一个由两个或多个派生类继承的基类,则以下内容将编译,但由于切片而无法按预期工作:

static base a[] = { derived1(), derived2() };

像这样的事情不应该导致切片发生:

static derived1 d1;
static derived2 d2;
static base *a[] = { &d1, &d2 };

我的问题是:我怎样才能做同样的事情而不需要声明d1 and d2分别于a,同时保留单个(指向)元素的静态存储?以下给出了“获取临时地址”错误:

static base *a[] = { &derived1(), &derived2() };

也许可以定义一个constexpr可变参数模板函数?就像是:

template<typename... Args>
constexpr std::initializer_list<base *> base_array(Args... args) {
    ...
}

然后我可以写:

static base *a[] = base_ptr_array(derived1(), derived2());

也许这会有相同的“获取临时地址”问题,尽管我的想法是,由于这是一个 constexpr,它的工作方式类似于{ foo(), foo(), foo() }上面(其中doesn't创建临时文件)。


您可以使用一些模板来避免声明这些静态变量:

#include <tuple>
#include <array>
#include <type_traits>
#include <utility>

template<class Base, class... Ts>
struct foo {
    foo()
        : foo(Ts{}..., std::index_sequence_for<Ts...>{})
    {}
    std::tuple<Ts...> deriveds;
    std::array<Base*, sizeof...(Ts)> arr;

private:
    template<std::size_t... Is>
    foo(Ts... ts, std::index_sequence<Is...>)
        : deriveds(ts...)
        , arr{ &std::get<Is>(deriveds)...}
    {}
};


// test 
#include <iostream>

struct A {
    virtual void show() const {
        std::cout << "A\n";
    }
    virtual ~A() = default;
};
struct B: public A
{
    void show() const override {
        std::cout << "B\n";
    }
};
struct C: public A
{
    void show() const override {
        std::cout << "C\n";
    }
}; 

foo<A, A, B, C> f;

int main() {
    for ( A *ptr : f.arr ) {
        ptr->show();
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 C++ 中,如何在不使用 new 且不单独声明各个元素的情况下创建 `std::initializer_list` ? 的相关文章

随机推荐