在C ++中,如何在没有new的情况下创建`std :: initializer_list <base * =“”/>`而不单独声明单个元素?

时间:2018-02-18 11:34:13

标签: c++ templates inheritance initialization initializer-list

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

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

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

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

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

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

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

我的问题是:如何在不必d1d2分别声明astatic base *a[] = { &derived1(), &derived2() }; 的情况下,同时为个别(指向)元素保留静态存储空间?以下给出了临时&#34;的地址。错误:

constexpr

也许可以定义一个template<typename... Args> constexpr std::initializer_list<base *> base_array(Args... args) { ... } 可变参数模板函数?类似的东西:

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

然后我可以写:

{ foo(), foo(), foo() }

也许这会有相同的&#34;获取临时&#34;问题,虽然我的想法是因为这是一个constexpr,它的工作方式与上面的CONSTRAINT FOREIGN KEY(fk_EmployeeEmpID) REFERENCES Employee(EmpID) 类似(不会创建临时工具)。

2 个答案:

答案 0 :(得分:7)

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

#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();
    }
}

答案 1 :(得分:6)

老实说,我认为你正在尝试使用错误的工具来完成工作。以下是我的看法:

  1. 您需要数组元素的多态行为。
  2. 你有一组有限的课程。如果它是打开的,你将无法为数组编写初始值设定项。
  3. 这是&#34;关闭集&#34;多态性给我。你可以在中没有动态分配的情况下完成它。你甚至不需要这些类有一个共同的基类。只有你想要打电话的成员。所需要的只是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);