如何创建一个包含三种不同类型的向量的向量

How can I create a vector that holds three different types of vectors

本文关键字:向量 包含三 同类型 何创建 创建 一个      更新时间:2023-10-16

我有三个结构(Foo,Bar,Fruit(,我想要一个向量来容纳每个结构,就像vector<Foo> Foo_holder; vector<Bar> Bar_holder; vector<Fruit> Fruit holder;一样,然后我想尝试将所有这三个向量放入一个向量中。所以它应该像这样结束,Vector_holder是我希望知道如何创建的顶级向量:

Vector_holder
--- Foo_Holder
------Instance of Foo
--- Bar_holder
------Instance of Bar
--- Fruit_holder
------Instance of Fruit

我该怎么做?

可能的重复问题列出了一个问题,即向量必须相同大小或代码中断,并且我问题中的向量将大量改变大小。我也觉得这对初学者C++学习者比其他问题更有帮助。 我在这里找到的解决方案对我有用,总体上比近乎论文的长答案简单得多。我更像是C++初学者,因此欣赏这里更容易理解的答案。

每当这样的分组有意义时,我倾向于将其放入struct并因此命名。在这种情况下,

struct FooBarFruitHolder {
std::vector<Foo> foos;
std::vector<Bar> bars;
std::vector<Fruit> fruits;
};

然后您可以将其用作

std::vector<FooBarFruitHolder> vec;
vec.emplace_back();

例如,用对象填充它:

/* Add a Foo element to all FooBarFruitHolder instances. */
for (auto&& fooBarFruitHolder : vec)
fooBarFruitHolder.foos.emplace_back(/* Arguments passed to Foo ctor */);

命名在这里至关重要,因此请选择最适合您的应用程序的命名。当您将此嵌套数据结构的一部分传递到设置成员变量的函数中时,初始化也可能更容易阅读,例如

void initialize(std::vector<Foo>& foos)
{
foos.emplace_back(/* Arguments for first Foo object */);
foos.emplace_back(/* Arguments for second Foo object */);
}
initialize(vec.front().foos);

向量来保存每个结构,如向量Foo_holder; 向量 Bar_holder;矢量水果架;然后我想尝试把 所有这三个向量合二为一个向量。

解释你的(有点模棱两可的(陈述的一种方法是,你还需要一个包含所有 N 元素类型的向量。 (但我怀疑你会更喜欢lubgr的回答。

对于第三个向量,我建议你考虑多态性。


如果从接口类派生每个结构,也许

class FooBarFruit_t 
{
//...
virtual void whistle() = 0;
virtual void bounce()  = 0;
virtual void f1()      = 0;
virtual void f2()      = 0;
virtual void f3()      = 0;
virtual void reflect();
//...
}

然后,您可以轻松创建一个可以加载任何 N 类型的向量

std::vector<FooBarFruit_t*> holder;  

下一个挑战将是创建每个派生类可以支持的虚拟方法。

a( 它们可能是抽象的,f1((, f2(( ...

b(它们可能非常具体,例如whistle((,这是只有foo才能做的事情(酒吧和水果在被命令吹口哨((时不会采取任何行动(。

[我不确定这些典型的动画实例可能会采取什么样的行为,但软件是抽象真正有帮助的地方。


这给你买的是,在运行时,你不必知道你正在指挥什么样的FooBarFruit_t采取行动。

通过调用 f3((,每个实例(foo 或 bar 或水果(都会按照你的要求去做,每个 f3(( 只是满足你对该类型的期望。

如果实例不 reflect((,你可以实现一个 a( 不执行任何操作或 b( 调用 FooBarFruit_t::reflect(( 的方法。 或其他几个选项。

考虑您可能希望显示所有对象:

for (auto fbf : holder)  fbf->show();
for (auto fbf : holder)  fbf->diagnostic();  // or diagnostic
for (auto fbf : holder)  fbf->reset();       // or reset

有什么理由需要考虑这些不同吗?


不应该有一个地方,你觉得需要根据类型做一些特定的事情:

void something() {
for (auto fbf : holder) {
switch(fbf.type())
{ // vvvvv - enumeration of types
case   Foo: foosomething(); break;
case Fruit: fruitsomething(); break;
case   Bar: barsomething(); break;
default : assert(0); break;
}
}
}

但是没有人会阻止你这样做,你认为你必须这样做。

您可以使用 Boost 的 zip 迭代器将不同的向量"压缩"在一起:

vector<Foo> Foo_holder; 
vector<Bar> Bar_holder; 
vector<Fruit> Fruit holder; 
/* ... insert elements etc. */
auto start = boost::make_zip_iterator(
std::make_tuple(ia.begin(), d.begin(), ib.begin())
);
auto end = boost::make_zip_iterator(
std::make_tuple(ia.end(), d.end(), ib.end())
);

现在,这不会产生一个向量,只是一对迭代器。但是现在你可以将它们与STL算法一起使用。例如:

std::for_each(start, end, [](auto a_foo, auto a_bar, auto a_fruit) {
std::cout << "The Foo   element is " << foo << "n";
std::cout << "The Bar   element is " << bar << "n";
std::cout << "The Fruit element is " << fruit << "n";
}

您还可以使用这些迭代器来创建单个范围对象。例如,在回答中,@leemes我的一个相关问题对此进行了描述。