كيفية استخدام stdext :: hash_map حيث المفتاح هو كائن مخصص؟

StackOverflow https://stackoverflow.com/questions/1059545

  •  21-08-2019
  •  | 
  •  

سؤال

واستخدام STL C ++ hash_map ...

class MyKeyObject
{
    std::string str1;
    std::string str2;

    bool operator==(...) { this.str1 == that.str1 ... }
};

class MyData
{
    std::string data1;
    int data2;
    std::string etcetc;
};

ومثل هذا ...

MyKeyObject a = MyKeyObject(...);
MyData b = MyData(...);

stdext::hash_map <MyKeyObject, MyData> _myDataHashMap;
_myDataHashMap[ a ] = b;

وأحصل على حمولة كاملة من الأخطاء. هنا أول ثلاثة ...

<اقتباس فقرة>   

والخطأ 1 خطأ C2784: 'منطقي   الأمراض المنقولة جنسيا :: المشغل <(CONST   الأمراض المنقولة جنسيا :: _ شجرة <_Traits> و، CONST   الأمراض المنقولة جنسيا :: _ شجرة <_Traits> &) ': لا يمكن   نستنتج حجة القالب ل 'CONST   الأمراض المنقولة جنسيا :: _ شجرة <_Traits> & 'من' CONST   MyKeyObject 'ج: \ ملفات البرنامج \ مايكروسوفت   استوديو مرئي   8 \ VC \ تشمل \ ظيفية 143

     

والخطأ 2 خطأ C2784: 'منطقي   الأمراض المنقولة جنسيا :: المشغل <(CONST   الأمراض المنقولة جنسيا :: basic_string <_Elem، _Traits، _Alloc>   و، CONST _Elem *) ': لا يمكن أن نستنتج   حجة القالب ل 'CONST   الأمراض المنقولة جنسيا :: basic_string <_Elem، _Traits، _Alloc>   و'من' CONST   المهام :: MyKeyObject 'C: \ برنامج   ملفات \ البصرية ستوديو مايكروسوفت   8 \ VC \ تشمل \ ظيفية 143

     

والخطأ 3 خطأ C2784: 'منطقي   الأمراض المنقولة جنسيا :: المشغل <(CONST _Elem *، CONST   الأمراض المنقولة جنسيا :: basic_string <_Elem، _Traits، _Alloc>   و) ': لا يمكن أن نستنتج قالب   حجة ل 'CONST _Elem * من   "CONST MyDataObject 'C: \ برنامج   ملفات \ البصرية ستوديو مايكروسوفت   8 \ VC \ تشمل \ ظيفية 143

     

...

إذا أنا وضعت المفتاح لشيء بسيط مثل عدد صحيح كل شيء على ما يرام.

وماذا أفعل الخطأ ؟! ربما أحتاج أن تفعل شيئا مع القوالب؟

هل هناك (أسرع؟) طريقة أفضل للوصول إلى البيانات باستخدام كائن رئيسي مخصص مثل هذا؟

هل كانت مفيدة؟

المحلول

وحاول ما يلي، عملت بالنسبة لي في VS 2005. هذا هو الحل لكل من VS2005 المدمج في نوع hash_map في مساحة الاسم stdext فضلا عن زيادة unordered_map (المفضل). حذف أيهما كنت لا تستخدم.

#include <boost/unordered_map.hpp>
#include <hash_map>

class HashKey
{
public:
    HashKey(const std::string& key)
    {
        _key=key;
    }
    HashKey(const char* key)
    {
        _key=key;
    }

    // for boost and stdext
    size_t hash() const
    {
        // your own hash function here
        size_t h = 0;
        std::string::const_iterator p, p_end;
        for(p = _key.begin(), p_end = _key.end(); p != p_end; ++p)
        {
            h = 31 * h + (*p);
        }
        return h;
    }
    // for boost
    bool operator==(const HashKey& other) const
    {
        return _key == other._key;
    }

    std::string _key;
};

// for boost
namespace boost
{
    template<>
    class hash<HashKey>
    {
    public :
        std::size_t operator()(const HashKey &mc) const
        {
            return mc.hash();
        }
    };
}

// for stdext
namespace stdext
{
    template<>
    class hash_compare<HashKey>
    {
    public :
        static const size_t bucket_size = 4;
        static const size_t min_buckets = 8;

        size_t operator()(const HashKey &mc) const
        {
            return mc.hash();
        }

        bool operator()(const HashKey &mc1, const HashKey &mc2) const
        {
            return (mc1._key < mc2._key);
        }
    };
}

int _tmain(int argc, _TCHAR* argv[])
{
    {
        stdext::hash_map<HashKey, int> test;
        test["one"] = 1;
        test["two"] = 2;
    }

    {
        boost::unordered_map<HashKey, int> test(8); // optional default initial bucket count 8
        test["one"] = 1;
        test["two"] = 2;
    }

    return 0;
}

نصائح أخرى

لاستخدام جدول تجزئة، تحتاج إلى تحديد وظيفة تجزئة. تحتاج إلى إنشاء كائن وظيفة وهو ما يمثل دالة التي تأخذ كائن MyKeyObject وإرجاع size_t. ثم قمت بتمرير functor كما الوسيطة الثانية بعد الحجم الأولي:

hash_map <MyKeyObject, MyData> _myDataHashMap(initial_size, YourHashFunctor());

وبدلا من ذلك، يمكنك كتابة دالة تجزئة الخاص بك كما التخصص قالب من functor hash<T> لنوع الخاص بك؛ بهذه الطريقة لا تحتاج إلى تمرير في وظيفة تجزئة مخصصة.

وأنا لا أعرف لماذا كنت تحصل على هذه الأخطاء على وجه التحديد. ربما كان يحاول استخدام الكائن الخاص بك كما رمز التجزئة أو شيء من هذا؟ وعلى أية حال لا ينبغي أن يعمل من دون وظيفة تجزئة. والمحددة مسبقا وظائف تجزئة أنواع صحيح والسلاسل.

وأنا استخدامه لرسم الخرائط لبنية البيانات قمة الرأس.

#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <boost/unordered_map.hpp>



struct VERTEX
{
float x,y,z;
};

typedef boost::unordered_map<std::string, unsigned int> map;

int main()
{
VERTEX v1,v2,v3;

v1.x = 5.0; v1.y = 2.0; v1.z = 2.33333336;
v2.x = 5.0; v2.y = 2.0; v2.z = 2.32333336;
v3.x = 5.0; v3.y = 2.0; v3.z = 2.33333336;

unsigned int vertexSize = sizeof( VERTEX );
char * v1c = new char[vertexSize];
char * v2c = new char[vertexSize];
char * v3c = new char[vertexSize];

memcpy( v1c, &v1, vertexSize );memcpy( v2c, &v2, vertexSize );memcpy( v3c, &v3, vertexSize );
map mymap;

std::string aaa( v1c, vertexSize );
std::string bbb( v2c, vertexSize );
std::string ccc( v3c, vertexSize );

mymap[ aaa ] = 1;
mymap[ bbb ] = 2;

unsigned int a = mymap[ aaa ];
unsigned int b = mymap[ bbb ];
unsigned int c = mymap[ ccc ];


return 0;
}

وهذا مجرد مثال صغير، كيف أنا باستخدام الأنواع المخصصة. أنا فقط نسخ جزء من الذاكرة من البنية إلى شار * وبعد ذلك إنشاء سلسلة مع المعلمة الثاني، وهو الحجم، وحجم لا يقل أهمية عن يمكن أن تحتوي على بيانات الذاكرة أحرف فارغة. أنا لست بحاجة إلى أي إضافية مقارنة، الثرم وظائف ...

وجئت عبر هذا السؤال القديم جدا بينما كان يحاول العثور على نفس الجواب، والعثور على إجابات القائمة غير مفيدة حقا. في الوقت الحاضر نستخدم unordered_map إذا كنا نريد خريطة التجزئة، وأفضل طريقة لجعل الطبقة MyKeyObject بك صالحة للاستعمال كمفتاح في hash_map بشكل عام هو تحديد وظيفة تجزئة للطبقة، ونقول للمكتبة القياسية لاستخدام هذه الوظيفة تجزئة خرائط. وهذا يعني أننا يمكن إنشاء مثيل القالب خريطة دون توفير دائما وظيفة تجزئة.

يكيبيديا الصفحة على 'غير مرتبة الجمعياتي الحاويات في C ++ "يوفر وسيلة سهلة لاتباع سبيل المثال، I تخلت عليه قليلا وتطبيقها على قضيتك. أولا سنقوم تعريف دالة البعثرة بسيطة كوسيلة عضو:

#include <functional>
class MyKeyObject {
private:
    std::string str1;
    std::string str2;

public:
    inline size_t hash() const {
        return std::hash<std::string>()(str1) ^ std::hash<std::string>()(str2);
    }

    inline bool operator==(const MyKeyObject& other) const {
        return str1 == other.str1 && str2 == other.str2;
    }
};

في أجل جعل وظيفة التجزئة، ونحن XOR تجزئات جميع تضمنت الأشياء معا. ويتم ذلك باستخدام std::hash، قالب والتي لابد مثيل مع نوع الطفل. لاحظ أننا لا يمكن استخدام هذا كمعلمة قالب الثالثة إلى unordered_map. لاحظ أيضا CONST-يساوي المشغل.

والآن علينا أن نقول للمكتبة القياسية أن هذه هي وظيفة التجزئة لاستخدامها في القيم MyKeyObject:

namespace std {
    template <>
    class hash<MyKeyObject> {
    public:
        size_t operator()(const MyKeyObject &aMyKeyObject) const {
            return aMyKeyObject.hash();
        }
    };
}

وهذا يضيف التخصص القالب إلى فئة قالب std::hash، وتوفير عامل تجزئة الطبقة MyKeyObject. على سبيل المثال لا على صفحة ويكيبيديا يحدد مباشرة تجزئة هنا، بدلا من الدعوة إلى وظيفة التجزئة الذي هو عضو في الكائن - ولكن إذا كانت وظيفة التجزئة لديها للوصول أعضاء من القطاع الخاص، التي لن تعمل

والآن يجب أن تكون قادرا على استخدام MyKeyObject في unordered_map مثل ذلك:

  std::unordered_map<MyKeyObject, MyData> _myDataHashMap;

و(اختبار مع رنة / كسكودي)

scroll top