6

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;

大量のエラーが発生します。最初の3つはこちら...

エラー 1 エラー C2784: 'bool std::operator <(const std::_Tree<_Traits> &,const std::_Tree<_Traits> &)' : 'const std::_Tree<_Traits> のテンプレート引数を推測できませんでした&' from 'const MyKeyObject' c:\program files\microsoft visual studio 8\vc\include\functional 143

エラー 2 エラー C2784: 'bool std::operator <(const std::basic_string<_Elem,_Traits,_Alloc> &,const _Elem *)' : 'const std::basic_string<_Elem,_Traits, _Alloc> &' from 'const Tasking::MyKeyObject' c:\program files\microsoft visual studio 8\vc\include\functional 143

エラー 3 エラー C2784: 'bool std::operator <(const _Elem *,const std::basic_string<_Elem,_Traits,_Alloc> &)' : 'const MyDataObject' から 'const _Elem *' のテンプレート引数を推定できませんでした c :\program files\microsoft ビジュアル スタジオ 8\vc\include\functional 143

...

キーを int のような単純なものに設定すると、すべて問題ありません。

私は何を間違っていますか?! 多分私はテンプレートで何かをする必要がありますか?

このようなカスタム キー オブジェクトを使用してデータにアクセスするより良い (より速い?) 方法はありますか?

4

4 に答える 4

2

以下を試してください。VS 2005 でうまくいきました。これは、stdext 名前空間の VS2005 組み込み hash_map タイプとブースト 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;
}
于 2010-03-09T22:10:54.357 に答える
0

頂点データの構造体のマッピングに使用しています。

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

これはほんの一例であり、カスタムタイプをどのように使用しているかです。構造体のメモリの一部を char* にコピーするだけで、サイズである 2 番目のパラメータで文字列を作成します。メモリ データには null 文字が含まれる可能性があるため、サイズは重要です。追加の比較、ハッシュ関数は必要ありません...

于 2013-01-18T16:02:59.643 に答える
0

同じ答えを見つけようとしているときに、この非常に古い質問に出くわしましたが、既存の回答はあまり役に立ちません。現在unordered_map、ハッシュマップが必要な場合に使用します。MyKeyObjectクラスを hash_map のキーとして一般的に使用できるようにする最善の方法は、クラスのハッシュ関数を定義し、標準ライブラリにこのハッシュ関数をマップに使用するように指示することです。これは、常にハッシュ関数を提供しなくても、マップ テンプレートをインスタンス化できることを意味します。

「C++ の Unordered Associative Containers」に関するウィキペディアのページには、わかりやすい例が示されています。私はそれを少し馬鹿にして、あなたのケースに適用しました。まず、単純なハッシュ関数をメンバー メソッドとして定義します。

#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 の 3 番目のテンプレート パラメーターとして使用できないことに注意してください。const-equals 演算子にも注意してください。

ここで、これが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;

(clang/xcode でテスト済み)

于 2014-07-02T22:48:36.733 に答える