我对 STL 很陌生,对 C++ 也很陌生。我正在尝试获得 .NET 的等价物 Dictionary<string, value>(StringComparer.OrdinalIgnoreCase)
但在 C++ 中。这大致就是我正在尝试的:
stdext::hash_map<LPCWSTR, SomeStruct> someMap;
someMap.insert(stdext::pair<LPCWSTR, SomeStruct>(L"a string", struct));
someMap.find(L"a string")
someMap.find(L"A STRING")
问题是,查找操作通常都不起作用(它返回 someMap.end()
)。它似乎有时有效,但大多数时候无效。我猜 hash_map 使用的散列函数是散列字符串的内存地址而不是字符串本身的内容,而且它几乎肯定不是不区分大小写的。
如何获得使用不区分大小写的键并可以存储自定义结构的类似字典的结构?
最佳答案
您链接到的 hash_map 文档表明您可以提供自己的特征类作为第三个模板参数。这必须满足与 hash_compare 相同的接口(interface).
浏览文档,我认为你必须做的是这个,它基本上取代了你在字典中使用的 StringComparer.OrdinalIgnoreCase
:
struct my_hash_compare {
const size_t bucket_size = 4;
const size_t min_buckets = 8;
size_t operator()(const LPCWSTR &Key) const {
// implement a case-insensitive hash function here,
// or find something in the Windows libraries.
}
bool operator()(const LPCWSTR &Key1, const LPCWSTR &Key2) const {
// implement a case-insensitive comparison function here
return _wcsicmp(Key1, Key2) < 0;
// or something like that. There's warnings about
// locale plastered all over this function's docs.
}
};
尽管文档说比较函数必须是全序,而不是 C++ 标准库中已排序容器通常采用的严格弱序,但我还是很担心。如果 MS 真的意味着总顺序,那么 hash_map 可能依赖于它与 operator==
一致。也就是说,他们可能要求如果 my_hash_compare()(a,b)
为假,并且 my_hash_compare()(b,a)
为假,则 a == b
。显然,我所写的内容并非如此,在这种情况下,你就不走运了。
作为替代方案,在任何情况下都可能更有效,您可以在 map 中使用它们之前将所有键推送到一个通用案例。不区分大小写的比较比常规字符串比较的成本更高。不过,有一些 Unicode 陷阱与我一直不太记得的有关。也许你必须转换 -> 小写 -> 大写,而不仅仅是 -> 大写,或类似的东西,以避免某些语言或标题字符出现一些令人讨厌的情况。有人吗?
另外正如其他人所说,您可能并不真正希望将 LPCWSTR 作为您的 key 。这将在映射中存储指针,这意味着任何插入字符串的人都必须确保它指向的数据只要在 hash_map 中就保持有效。从长远来看,hash_map 保留传递给 insert
的 key 字符串的 拷贝 通常会更好,在这种情况下,您应该使用 wstring
作为关键。
关于c++ - 如何使用不区分大小写的 unicode 字符串作为键的 hash_map?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1949997/