包含不同类型的STL容器?

时间:2013-10-01 15:53:19

标签: c++ templates stl

假设我有不同类型的组件,它们是结构。也许我有TransformComponentRigidBodyComponent

现在,这就是问题所在:我想要一个像std::map这样的东西,你可以将组件类型和id映射到组件。 ID是将组件链接在一起的东西。我应该使用什么样的容器呢?我无法使用std::map<std::typeindex, std::map<id_t, T>>,因为类型T取决于您使用哪种类型索引来索引第一张地图。

4 个答案:

答案 0 :(得分:1)

您的用例听起来像是多态性的典型用法。您应该知道,在单个容器中存储“非同类”类型的任何尝试都会带来多态性的性能损失。至于你是否会使用C ++提供的“开箱即用”多态,或者使用自定义解决方案 - 它完全取决于你。

顺便说一句,引用该问题评论中的一个问题:

  

假设您可以拥有这样的容器。你会怎么做?能够   你展示了一些预期的用法例子吗?

这是一个非常好的问题,因为揭示您的特定使用场景将允许其他人更详细地回答您的问题,因为现在听起来您并不真正知道您正在做什么或需要做什么。所以,如果你需要进一步的指导,你应该真正澄清并建立你的问题。

答案 1 :(得分:0)

如果您需要使用包含不同类型的容器,请查看一些BOOST库:
任何:适用于不同值类型的单个值的安全通用容器。 (http://www.boost.org/doc/libs/1_54_0/doc/html/any.html
变体:安全,通用,基于堆栈的歧视联合容器(http://www.boost.org/doc/libs/1_54_0/doc/html/variant.html

如果您的类型列表定义明确且不会更改,请使用变体

所以你的代码看起来像这样:

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。

答案 2 :(得分: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个字节而一个浮点数需要4个字节,那么即使我只存储ent它也会为floats分配空间,所以我将浪费4个字节每次我存储ent。根据应用程序的用途和存储类型的大小,这可能会忽略不计。
  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; }

答案 3 :(得分:0)

boost :: any或boost :: any_cast ??

怎么样?

http://www.boost.org/doc/libs/1_54_0/doc/html/any.html