在C++中,如何在没有新元素且不单独声明单个元素的情况下创建"std::initializer_list<base *>"?

In C++, how can I create a `std::initializer_list<base *>` without new and without declaring individual elements separately?

本文关键字:元素 情况下 创建 std initializer list gt base lt 声明 C++      更新时间:2023-10-16

在C 中,您可以在文件范围上声明某些内容:

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

单个foo对象具有静态存储(即,在运行时未分配它们(。

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

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

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

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

我的问题是:如何在不必与a分开声明d1d2的情况下执行相同的操作,而在为个人(尖头(元素保留静态存储时?以下给出了"临时地址"错误:

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

也许可以定义 constexpr variadic模板函数?类似:

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

然后我可以写:

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

也许这会有相同的"暂时地址"问题,尽管我的想法是,由于这是一个constexpr,它的工作方式与上面的{ foo(), foo(), foo() }相似( create extence exture exture exturearies(。

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

#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 << "An";
    }
    virtual ~A() = default;
};
struct B: public A
{
    void show() const override {
        std::cout << "Bn";
    }
};
struct C: public A
{
    void show() const override {
        std::cout << "Cn";
    }
}; 
foo<A, A, B, C> f;
int main() {
    for ( A *ptr : f.arr ) {
        ptr->show();
    }
}

说实话,我认为您正在尝试将错误的工具用于工作。这是我看到的:

  1. 您想要来自数组元素的多态性行为。
  2. 您有一组有限的课程。如果打开的话,您将无法为数组编写初始化器。

这对我来说是"封闭的"多态性。您可以在C 17中无动态分配而实现它。您甚至不需要课程就可以拥有一个普通的基础课。只有您希望打电话给相同的成员。它所需要的是类型的std::variant和一系列变体:

using variant_type = std::variant<derived1, derived2, ..., derived_n>;
static variant_type a[] = {
  derived1(), derived2(), ..., derived_n()
}; 

,你有它。您获得了多态性行为,只需要std::visit一个数组元素,而不是通过指针调用成员函数:

for(auto& v : a)
  std::visit([](auto& e) {
    // Do something with e
    // It's a reference to one of the types the variant can hold
  }, v);
相关文章: