使用不同的类存储对象成员变量的引用

时间:2011-05-14 06:00:28

标签: c++ templates

我正在尝试创建一个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

4 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:0)

template <typename dataType>
dataType Object::* memberVariable; //  error 

声明 tempate 数据成员?这是C ++不允许的。我不能建议任何替代方案,因为我实际上并不明白你究竟想要做什么。

为什么不首先尝试使用标准库提供的容器?您是否看到了std::vectorstd::liststd::map等以及来自<algorithm>的通用函数?

答案 2 :(得分: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 ++代码。您可以在运行时决定要用作键的成员(第二个版本),但其类型必须在编译时修复。

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

答案 3 :(得分:0)

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

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

template<typename Object>
class Container
{
  typename Object::ObjectVariablePtrType memberVariable;
};