Store a reference to a member variable of an object with another class

I am trying to create a container class where I can get an object from a container using this member variable as its identifier. But I get a compilation error because I'm trying to save a pointer (?) / Link to an object member variable

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 
+6
source share
4 answers

Declaring a template data element is not allowed in C ++ (not to be confused with the template syntax used when defining a static member). The best way to achieve is

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

Declaring a tempate data member? This is forbidden by C ++. And I canโ€™t offer you any alternative, because I donโ€™t understand what exactly you are trying to do.

Why don't you try using the containers provided by the standard library? You saw std::vector , std::list , std::map , etc. Together with the common functions from <algorithm> ?

0
source

The following are two options for what you are requesting: the first in which the element is a template parameter, and the second in which the element is instead passed as an argument when building the map ...

 #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; } 

Basically you need to move at least a member type as a template parameter, because it is necessary to be able to generate C ++ code on the map. At run time, you can decide which member you want to use as a key (second version), but its type must be fixed at compile time.

If instead of the actual member that you want to use as a key, compilation time is known, then the member pointer can be taken into account as a template parameter (first version), generating more efficient code (however, creating a new class for every other member - thus increasing the size compiled code).

0
source

you can leave by declaring a member type like this.

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

Source: https://habr.com/ru/post/888092/


All Articles