简体   繁体   English

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

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

In C++, you can declare an array of something at the file scope: 在C ++中,您可以在文件范围内声明某个数组:

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

The individual foo objects have static storage (ie they are not allocated at run-time). 各个foo对象具有静态存储(即它们不在运行时分配)。

If I had a base class inherited by two or more derived classes, the following would compile but not work as expected due to slicing: 如果我有一个由两个或多个派生类继承的基类,则由于切片,以下内容将编译但不能按预期工作:

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

Something like this should not cause slicing to happen: 这样的事情不应该导致切片发生:

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

My question is: How can I do the same without having to declare d1 and d2 separately from a , and while keeping static storage for the individual (pointed-to) elements? 我的问题是:我怎么可以这样做,而不必申报d1d2分别从a ,并同时保持静态存储的个人(指向的)元素呢? The following gives a "taking address of temporary" error: 以下给出了“获取临时”错误的地址:

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

Maybe it would be possible to define a constexpr variadic template function? 也许有可能定义一个constexpr可变参数模板函数? Something like: 就像是:

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

Then I could write: 然后我可以写:

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

Maybe this would have the same "taking address of temporary" problem, though my idea was that since this is a constexpr it would work similarly to { foo(), foo(), foo() } above (which doesn't create temporaries). 也许这会有同样的“暂时解决”问题,虽然我的想法是,因为这是一个constexpr,它的工作方式与上面的{ foo(), foo(), foo() }类似( 不会产生临时性) )。

You can use some template to avoid declaring those static variables: 您可以使用一些模板来避免声明这些静态变量:

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

To be honest, I think you are trying to use the wrong tool for the job. 说实话,我认为你正在尝试使用错误的工具来完成工作。 Here's how I see it: 这是我的看法:

  1. You want polymorphic behavior from the array elements. 您需要来自数组元素的多态行为。
  2. You have a finite set of classes you care about. 你有一组有限的课程。 If it was open, you wouldn't be able to write an initializer for an array. 如果它是打开的,您将无法为数组编写初始值设定项。

This reads "closed set" polymorphism to me. 这给我读了“闭集”多态。 And you can accomplish it without dynamic allocation in . 你可以在没有动态分配的情况下完成它。 You don't even need the classes to have a common base class. 您甚至不需要类具有公共基类。 Only to have the same members you wish to call. 只有你想要打电话的成员。 All it takes is a std::variant of types, and an array of variants: 所需要的只是类型的std::variant和一组变体:

using variant_type = std::variant<derived1, derived2, ..., derived_n>;

static variant_type a[] = {
  derived1(), derived2(), ..., derived_n()
}; 

And there you have it. 你有它。 You get your polymorphic behavior, just need to std::visit an array element instead of calling a member function via pointer: 你得到了你的多态行为,只需要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);

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

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