Сохраните ссылку на переменную-член объекта с другим классом - PullRequest
6 голосов
/ 14 мая 2011

Я пытаюсь создать класс 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 ]

1 голос
/ 14 мая 2011

Объявление элемента данных шаблона недопустимо в C ++ (не путать с синтаксисом шаблона, используемым при определении статического элемента). Лучший способ добиться этого -

template <typename Object, typename dataType>  // <-- Add dataType here
class Container
{
     private:
         dataType Object::* memberVariable; // use 'dataType' simply
// ...
};
0 голосов
/ 27 августа 2011

вы можете уйти, объявив тип члена следующим образом.

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

template<typename Object>
class Container
{
  typename Object::ObjectVariablePtrType memberVariable;
};
0 голосов
/ 14 мая 2011

Ниже приведены два варианта того, что вы запрашиваете: первое, в котором элемент является параметром шаблона, и второе, в котором элемент вместо этого передается в качестве аргумента при построении карты ...

#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 ++ карты. Вы можете решить во время выполнения, какой элемент вы хотите использовать в качестве ключа (вторая версия), но его тип должен быть зафиксирован во время компиляции.

Если вместо этого даже фактический член, который вы хотите использовать в качестве ключа, известен как время компиляции, тогда указатель члена может быть разложен как параметр шаблона (первая версия), генерируя более эффективный код (однако создавая новый класс для каждого другого member - таким образом увеличивая размер скомпилированного кода).

0 голосов
/ 14 мая 2011
template <typename dataType>
dataType Object::* memberVariable; //  error 

Объявление элемента tempate ?Это не разрешено C ++.И я не могу вам предложить какую-либо альтернативу, потому что я на самом деле не понимаю, что именно вы пытаетесь сделать.

Почему бы вам сначала не попробовать использовать контейнеры, предоставляемые стандартной библиотекой?Вы видели std::vector, std::list, std::map и т. Д. Вместе с общими функциями из <algorithm>?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...