[英]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? 我的问题是:我怎么可以这样做,而不必申报
d1
和d2
分别从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:
这是我的看法:
This reads "closed set" polymorphism to me. 这给我读了“闭集”多态。 And you can accomplish it without dynamic allocation in c++17 .
你可以在没有c ++ 17动态分配的情况下完成它。 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.