2011-05-14 55 views
6

我想创建一个Container类,我可以通过使用该对象成员变量作为其标识符从容器中检索对象。 但我得到一个编译错误,因为我想存储指针(?)/参照对象的成员变量存储对一个不同类的对象成员变量的引用

template <typename Object> 
class Container 
{ 
    private: 
     template <typename dataType> 
     dataType Object::* memberVariable; // error here "data member 'memberVariable' cannot be a member template" 

     template <typename dataType> 
     std::map <dataType, Object*>  instanceVarMap; // what would be more efficient; a Map or unordered_map? I heard that 
     std::map <unsigned int, Object*> instanceIntMap; // ...unordered_maps use more memory & Maps are better when integers are the keys 

    public; 
     template <typename dataType> 
     Collection(dataType Object::*nMemberVariable) 
     { 
      memberVariable = nMemberVariable; 
     } 

     template <typename dataType> 
     Object* operator[] (dataType nParam) 
     { 
      // do I need to check whether the element already exists or does 
      // stl already do this for me? 
      if (instanceVarMap.find(nParam) == instanceVarMap.end()) 
      { 
        return NULL; 
      } 

      return instanceVarMap[ nParam ]; 
     } 

     Object* operator[] (unsigned int nParam) 
     { 
      if (instanceIntMap.find(nParam) == instanceIntMap.end()) 
      { 
        return NULL; 
      } 

      return instanceIntMap[ nParam ]; 
     } 

     void store(Object* o) 
     { 
       if (o==NULL || instanceMap.contains(o->memeberVariable) != instanceMap.end()) { return; } 

       instanceIntMap.insert(o->ID, o); 
       instanceVarMap.insert(o->memberVariable, o); // is this the correct way I get the objects member variable? o->memberVariable 
     } 
}; 


// I am doing this so I can use the class like so 
struct FoodItem 
{ 
    unsigned int ID; 
    string name; 
    double price; 
}; 

Collection <FoodItem*> foodCol(&FoodItem::name); 

// after storing some FoodItems in foodCol, I can retreive a FoodItem either 
// by their ID or their name 
FoodItem* f = foodCol["coffee"]; // find FoodItem by their member variable 'name' 
FoodItem* g = foodCol[1];   // find FoodItem by their ID var 
+0

这是什么:'集合 foodCol(&FoodItem :: name);'应该是什么意思?什么地址? – 2011-05-14 06:06:02

+0

我想你的意思是&FoodItem :: name是什么意思,我指的是结构FoodItem的成员变量名称。因此,我创建了一个Collection并且我希望能够通过使用它们的名称作为关键字(标识符)来访问它的FoodItem元素 – user593747 2011-05-14 06:09:19

回答

1

在C++中不允许声明模板数据成员(不要与定义静态成员时使用的模板语法混淆)。为了达到最好的办法是,

template <typename Object, typename dataType> // <-- Add dataType here 
class Container 
{ 
    private: 
     dataType Object::* memberVariable; // use 'dataType' simply 
// ... 
}; 
0
template <typename dataType> 
dataType Object::* memberVariable; // error 

声明一个tempate数据成员?这是C++不允许的。我不能提出任何其他建议,因为我实际上并不明白你想要做什么。

为什么不首先尝试使用标准库提供的容器?你见过std::vector,std::list,std::map等,以及从<algorithm>的一般功能?

+0

什么?我知道我可以这样做int Object :: * memberVariable我不知道编译时的memberVariable的数据类型,有什么我可以做的吗? – user593747 2011-05-14 06:10:56

+0

@ user593747:如果你不知道成员的数据类型,那么在编译时,你不能做你想做的事。 C++是一种静态类型语言,这意味着每个变量的类型必须在编译时已知。 – Nawaz 2011-05-14 06:13:52

+0

你可以......假设至少成员**类型**在编译时已知。看到我的答案(第二种情况)。 – 6502 2011-05-14 06:38:38

0

在下面也有你问了两个变化:第一,其中成员是一个模板参数,并在该成员,而不是作为传递的第二建立参数时,地图...

#include <map> 
#include <string> 
#include <iostream> 

template<typename Object, typename MemberType, MemberType Object::*member> 
struct MemberMap 
{ 
    std::map<MemberType, Object *> mmap; 

    Object * operator[](const MemberType& mv) const 
    { 
     typename std::map<MemberType, Object *>::const_iterator i = mmap.find(mv); 
     return i == mmap.end() ? NULL : i->second; 
    } 

    void store(Object *o) 
    { 
     if (o && mmap.find(o->*member) == mmap.end()) 
      mmap[o->*member] = o; 
    } 
}; 

template<typename Object, typename MemberType> 
struct MemberMapByInst 
{ 
    MemberType Object::*member; 
    std::map<MemberType, Object *> mmap; 

    MemberMapByInst(MemberType Object::*member) : member(member) 
    { 
    } 

    Object * operator[](const MemberType& mv) const 
    { 
     typename std::map<MemberType, Object *>::const_iterator i = mmap.find(mv); 
     return i == mmap.end() ? NULL : i->second; 
    } 

    void store(Object *o) 
    { 
     if (o && mmap.find(o->*member) == mmap.end()) 
      mmap[o->*member] = o; 
    } 
}; 

struct Foo 
{ 
    std::string name; 

    Foo(const std::string& name) : name(name) 
    { 
    } 
}; 

int main() 
{ 
    Foo foo1("This is a test"); 
    Foo foo2("This is another test"); 

    MemberMap<Foo, std::string, &Foo::name> namemap; 
    namemap.store(&foo1); 
    namemap.store(&foo2); 

    MemberMapByInst<Foo, std::string> namemap2(&Foo::name); 
    namemap2.store(&foo1); 
    namemap2.store(&foo2); 

    std::cout << (namemap["This is a test"] != NULL) << std::endl; 
    std::cout << (namemap["What about this?"] != NULL) << std::endl; 
    std::cout << (namemap2["This is a test"] != NULL) << std::endl; 
    std::cout << (namemap2["What about this?"] != NULL) << std::endl; 

    return 0; 
} 

基本上你需要移动至少成员作为模板参数类型,因为需要的就是能够生成地图的C++代码。你可以在运行时决定你想用什么作为键(第二个版本),但是它的类型必须在编译时修正。

如果相反,即使您想用作键的实际成员已知编译时间,那么成员指针也可以作为模板参数(第一版本)分解出来,从而生成更高效的代码(但为每个代码创建一个新类不同的成员 - 从而增加编译的代码大小)。

+0

有没有办法通过这种方法存储指向对象的指针?所以我可以做这个MemberMap persistantObjectMap; – user593747 2011-05-21 03:22:45

0

你可以通过声明这样的成员类型逃脱。

struct MyObject 
{ 
int Variable; 
typedef int MyObject::* ObjectVariablePtrType; 
}; 

template<typename Object> 
class Container 
{ 
    typename Object::ObjectVariablePtrType memberVariable; 
}; 
相关问题