C ++在一个集合中存储多种数据类型

时间:2012-03-19 18:32:00

标签: c++ data-structures

问题:我希望我的代码的不同部分能够访问存储不同类型对象的公共集合,以便知道每个对象的类型,并且至关重要的是,检索从集合中应该在编译时进行类型检查。 (我意识到这与以前提出的问题很接近,但请继续阅读,这有点具体。)

举一个具体的例子,我想要做以下事情:

// Stuff that can go in the collection:
enum Key { NUM_APPLES /* (unsigned int) */, APPLE_SIZE /* (double) */ }
map<Key, Something> collection;

unsigned int * nApples = collection.find(NUM_APPLES);
int * appleSize = collection.find(APPLE_SIZE); // COMPILATION ERROR - WRONG TYPE

我的解决方案:到目前为止,我已使用boost::any设计了以下解决方案:

关键:

using namespace std;
using namespace boost::any;

struct KeySupertype
{
protected:
    // Can't create an instance of this type
    KeySupertype() {}
private:
    // Can't copy
    KeySupertype& operator = (const KeySupertype& other) {}
    KeySupertype(const KeySupertype& other) {}
};

template <typename Type>
struct Key : public KeySupertype
{
public:
    Key() {}
};

收藏品:

class PropertiesMap
{
public:
    template<typename T>
    T * find(Key<T> & key);

    /* Skipping erase, insert and other methods for brevity. */

private:
    map<const KeySupertype *, any> myAnyMap;
};

template <typename T>
T * PropertiesMap::find(Key<T> & key)
{
    const map<const KeySupertype *, any>::iterator it = myAnyMap.find(&key);

    if(it == myAnyMap.end())
        return NULL;

    return any_cast<T>(&it->second);
}

用法:

static const Key<unsigned int> NUM_APPLES;
static const Key<double> APPLE_SIZE;

PropertiesMap collection;

/* ...insert num apples and apple size into collection ...*/

unsigned int * const nApples = collection.find(NUM_APPLES);
int * const nApples = collection.find(NUM_APPLES); // COMPILATION ERROR

这种类型信息根据其模板参数使用每个Key进行编码,因此在与集合交互时将强制执行类型。

问题:

1)这是实现目标的合理方式吗?

2)令人讨厌的是,集合使用Key个对象的地址作为内部std::map键。有没有解决的办法?或者至少是减轻误用的一种方法?我尝试在int生成的每个密钥中使用唯一的static int(并使std::map密钥类型为int),但我想如果可能出于线程原因,请避免静态。

3)要避免使用boost::anystd::map类型为<const KeySupertype *, void *>并使用static_cast<T>代替any_cast是否合理?< / p>

1 个答案:

答案 0 :(得分:0)

1)对我来说很好,一个聪明的解决方案

2)我猜你害怕有人会复制密钥,而且它的地址也会改变。如果这是您的问题,请在KeySuperType中保留“原始地址”字段。在构造期间将原始地址设置为此,在复制期间将原始地址设置为右手(源)的原始地址。使用此原始地址访问地图内容。我真的想不出编译时解决方案,因为在编译时,编译单元不会彼此了解。您可以在链接时间最早为键分配唯一ID,并获取全局变量的地址等同于此。我能用这个解决方案看到的唯一弱点是,如果你在没有extern的两个动态共享库中定义相同的密钥,它们将默默地拥有自己的具有不同地址的密钥版本。当然,如果所有内容都进入相同的二进制文件,那么就不会有这个问题,因为没有extern的两个声明会导致“多个声明”链接器错误。

3)如果boost::any的问题取决于提升(你认为这更好),那么自己实施any,这非常简单。如果问题是性能问题,那么static_cast<>对我来说似乎也没关系,只要你保留PropertiesMap的内部结构 远离那些不知道他们在做什么的人......