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

Store a reference to an objects member variable with a different class

本文关键字:对象 成员 变量 引用 同类 存储      更新时间:2023-10-16

我正在尝试创建一个容器类,我可以通过使用对象成员变量作为其标识符从容器中检索对象。但是我收到编译错误,因为我正在尝试存储指针(?/对对象成员变量的引用

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

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

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

声明临时数据成员?这是C++不允许的。 我不能提出任何替代方案,因为我实际上不明白你到底想做什么。

为什么不先尝试使用标准库提供的容器? 您是否见过std::vectorstd::liststd::map等,以及<algorithm>的泛型函数?

在下面,您要求的内容有两种变体:第一种是成员是模板参数,第二种是在构建地图时将成员作为参数传递的......

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

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

您可以通过

像这样声明成员类型来摆脱困境。

struct MyObject
{
 int Variable;
 typedef int MyObject::* ObjectVariablePtrType;
};
template<typename Object>
class Container
{
  typename Object::ObjectVariablePtrType memberVariable;
};