不同类型的STL容器?

4
假设我有不同类型的组件,它们都是结构体。也许我有TransformComponent和RigidBodyComponent。
现在问题来了:我想要一个类似于std::map的东西,可以将组件类型和id映射到组件上。ids是连接组件的关键。应该使用什么容器来实现?不能使用std::map>,因为类型T取决于您用于索引第一个映射的typeindex。

1
“TransformComponent”和“RigidBodyComponent”有类似的接口吗?如果是这样,您可以从共同的基类派生它们,并存储实例的智能指针。 - milleniumbug
它们是普通的数据类型,实际上彼此之间没有关系。 - user2827100
一般来说,STL标准容器是同质的;它们都存储单一类型的项目。您可以通过继承和存储指针来放松这种限制。 - Marshall Clow
嗯,也许我会存储指向内部容器的指针。 - user2827100
2
暂时把“哪一个”这个问题放在一边。假设你可以拥有这样的容器,你会用它来做什么?你能展示一些预期使用的例子吗? - n. m.
显示剩余2条评论
4个回答

1
您的使用情况听起来像是多态性的典型应用。您应该知道,将“非同类”类型存储在单一容器中的任何尝试都将带来多态性的性能损失。至于您是否将使用C++提供的“开箱即用”的多态性,还是采用自定义解决方案 - 这完全取决于您。
另外,引用问题评论中的一个问题:
假设您可以拥有这样的容器。 您会怎么做?您可以展示一些预期使用示例吗?
这是一个非常好的问题,因为揭示您特定的用法场景将允许其他人更详细地回答您的问题,因为现在它听起来像您并不真正知道自己在做什么或需要做什么。因此,如果您需要进一步的指导,请确实澄清和补充您的问题。

我基本上想要创建一个实体系统(http://t-machine.org/index.php/2007/09/03/entity-systems-are-the-future-of-mmog-development-part-1/)。 - user2827100
这里有一个示例实现 - http://entity-systems.wikidot.com/test-for-parallel-processing-of-components#cpp,同时你可能想要了解一下数据导向和数据导向设计的相关知识。 - dtech

0

0
如果您需要使用包含不同类型的容器,请查看一些BOOST库:
Any:安全的通用容器,用于不同值类型的单个值。(http://www.boost.org/doc/libs/1_54_0/doc/html/any.html)
Variant:安全的通用、基于堆栈的区分联合容器(http://www.boost.org/doc/libs/1_54_0/doc/html/variant.html)

如果您的类型列表已经定义好且不会改变,请使用variant

因此,您的代码可能如下所示:

typedef boost::variant<TransformComponent, RigidBodyComponent> my_struct;
std::map<std::typeindex, std::map<id_t, my_struct> > cont;
...
std::typeindex index = std::type_index(typeid(TransformComponent));
std::map<id_t, my_struct> & m = cont[index];
id_t id = ...;
TransformComponent & component = boost::get<TransformComponent>(m[id]);

这段代码相当丑陋,因此考虑更改架构。也许使用boost::any或boost::variant会更简单。

P.S. 如果您编写模板代码,则最好查看boost::mpl。


0

如果您不介意编写使用古老的C语言技巧的自定义容器,那么您可以解决这个问题。

我在这里为您编写了一个示例:

#include <iostream>

using namespace std;

struct ent
{
    int myInt;
};

struct floats
{
    float float1;
    float float2;
};

struct container
{
    bool isTypeFloats;

    union
    {
        ent myEnt;
        floats myFloats;
    };
};

void main( void )
{
    ent a = { 13 };
    floats b = { 1.0f, 2.0f };
    container c;
    container d;

    cout << b.float1 << " " << b.float2 << endl;

    c.isTypeFloats = false;
    c.myEnt = a;

    d.isTypeFloats = true;
    d.myFloats = b;

    //correct accessor
    if( c.isTypeFloats )
    {
        cout << c.myFloats.float1 << " " << c.myFloats.float2 << endl;
    }
    else
    {
        cout << c.myEnt.myInt << endl;
    }

    if( d.isTypeFloats )
    {
        cout << d.myFloats.float1 << " " << d.myFloats.float2 << endl;
    }
    else
    {
        cout << d.myEnt.myInt << endl;
    }
}

如果要将这些结构体放入容器中,您只需执行以下操作:std::vector< container >

有几件事情您需要知道:

  1. 联合体为最大类型分配空间。因此,在我的示例中,如果int占用4个字节,float占用4个字节,那么即使我只存储一个ent,它也会为floats分配空间,所以每次存储ent时都会浪费4个字节。根据您的应用程序目的和存储的类型大小,这可能是可以忽略的。
  2. 如果您存储的类型大小存在显著差异,则可以按照C++在幕后实际处理联合体的方式进行操作。这就是使用void*。因此,您将执行以下操作:std::vector< void* > myVec,并插入如下:myVec.push_back( &x ),其中x是您的类型,例如我们示例中的ent。但是,在读取它时,您必须知道您指向的是什么,因此您必须知道要执行类似于以下内容的操作:cout << ( ( ent* )myVec[0] )->myInt << endl;
  3. 因为您可能不知道它是什么类型,除非您有一些预定义的写入模式,否则您可能只想使用容器结构,如下所示:

    struct container2 { bool isTypeFloats; void* myUnion; }


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接