unordered_map使用MFC的CString作为键值遇到C2056和C2064错误

文章目录

unordered_map使用MFC的CString作为键值遇到C2056和C2064错误

问题出现的背景

在我的一个老工程项目中,使用C++的std::unordered_map时,使用了MFC的CString作为键值类型,遇到编译错误C2056和C2064。这些错误通常与哈希函数和比较操作符的缺失有关。

此前,项目使用了如下代码实现CString的哈希函数和比较操作符:

cpp 复制代码
// CString 哈希函数结构体,用于unordered_map
struct CStrHashFunc
{
	size_t operator()(const CString &str) const
	{
		return hash_value(static_cast<LPCTSTR>(str));
	}
};

代码是VS2015环境下实现的,然后当项目代码升级迁移到VS2022时,随着VC++版本的升级,hash_value这种非标准函数不再可用,参考unordered_map使用std::string作为键的办法,示例代码如下:

cpp 复制代码
#include <iostream>
#include <string>
#include <unordered_map>

int main()
{
    std::unordered_map<std::string, double> mymap = {
       {"mom",5.4},
       {"dad",6.1},
       {"bro",5.9},
		{"姐姐",5.5 }
    };

    std::string input;
    std::cout << "who? ";
    getline(std::cin, input);

    std::unordered_map<std::string, double>::const_iterator got = mymap.find(input);

    if (got == mymap.end())
        std::cout << "not found";
    else
        std::cout << got->first << " is " << got->second;

    std::cout << std::endl;

    return 0;
}

上述代码以unordered_map的查找为例,使用了std::string作为键值类型,并且可以直接使用std::hash<std::string>,不需要额外定义哈希函数。

然而,我们将这种思路放到CString上时,直接使用std::hash<CString>会导致编译错误C2056和C2064,因为标准库并没有为MFC的CString提供默认的哈希函数和比较操作符。

解决方案

为了解决这个问题,我们需要为CString自定义哈希函数和比较操作符。以下是一个示例代码,展示了如何实现这一点,该代码可以在VS2022中编译通过,且功能正常:

cpp 复制代码
// CString 比较函数结构体,用于unordered_map
struct CStrCmp
{
	bool operator()(const CString &str1, const CString &str2) const
	{
		return str1 == str2;
	}
};

// CString 哈希函数结构体,用于unordered_map
struct CStringHasher
{
	template <typename BaseType, class StringTraits>
	size_t operator()(const CStringT<BaseType, StringTraits>& _Keyval) const noexcept
	{ // hash _Keyval to size_t value by pseudorandomizing transform
		return std::_Hash_array_representation(_Keyval.GetString(), _Keyval.GetLength());
	}
};

// 应用示例:
unordered_map<CString, int, CStringHasher, CStrCmp> m_filemap;
unordered_map<CString, int, CStringHasher, CStrCmp>::const_iterator itr = m_filemap.find(filename);

在上述代码中,我们定义了两个结构体:

  1. CStrCmp:用于比较两个CString对象是否相等,重载了operator()
  2. CStringHasher:用于计算CString的哈希值,重载了operator(),利用了CStringT的成员函数GetString()GetLength()来获取字符串内容和长度,并调用了标准库的哈希函数。

当然,我们也可以在namespace std(std命名空间)中定义这哈希和比较运算(事实上这种情况下我们只需要定义哈希,因为这种模式下会默认使用CString自带的比较运算):

cpp 复制代码
namespace std
{
	template <typename BaseType, class StringTraits>
	struct hash<CStringT<BaseType, StringTraits>>
	{ // hash functor for CStringT<BaseType, StringTraits>
		size_t operator()(const CStringT<BaseType, StringTraits>& _Keyval) const noexcept
		{ // hash _Keyval to size_t value by pseudorandomizing transform
			return (_Hash_array_representation(_Keyval.GetString(), _Keyval.GetLength()));
		}
	};
} // namespace std

调用示例代码如下:

cpp 复制代码
std::unordered_map<CString, int> myMap = { {L"acad.lsp", 1}, {L"acaddoc.lsp", 1}, {L"acad.mnl", 2} };
std::unordered_map<CString, int>::const_iterator it = myMap.find(L"acad.lsp");

该代码编译和执行均正常。

总结

通过为MFC的CString自定义哈希函数和比较操作符,我们成功解决了在使用std::unordered_map时遇到的编译错误C2056和C2064的问题。这种方法不仅适用于CString,也可以推广到其他自定义类型,只要为它们提供合适的哈希函数和比较操作符即可。这样,我们就能充分利用unordered_map的高效查找性能,同时避免编译错误。

然而,CString类​​不是线程安全​​的。在多线程环境中,如果多个线程同时操作​​同一个​​ CString实例(例如作为 unordered_map的键并进行修改),可能会导致内存地址错误或进程异常退出。

相关推荐
li16709027013 分钟前
第二十七章:智能指针
c语言·数据结构·c++·visual studio
王老师青少年编程1 小时前
csp信奥赛C++高频考点专项训练之贪心算法 --【贪心与二分判定】:数列分段 Section II
c++·算法·贪心·csp·信奥赛·二分判定·数列分段 section ii
zh_xuan1 小时前
libcurl调用https接口
c++·libcurl
就叫飞六吧1 小时前
QT写一个桌面程序exe并动态打包基本流程(c++)
开发语言·c++
蜡笔小马1 小时前
1.c++设计模式-工厂模式
c++
汉克老师2 小时前
GESP2025年3月认证C++五级( 第三部分编程题(2、原根判断))
c++·算法·模运算·gesp5级·gesp五级·原根·分解质因数
winner88812 小时前
从零吃透C++命名空间、std、#include、string、vector
java·开发语言·c++
AI进化营-智能译站2 小时前
ROS2 C++开发系列07-高效构建机器人决策逻辑,运算符与控制流实战
开发语言·c++·ai·机器人
winner88812 小时前
C++ 命名空间、虚函数、抽象类、protected 权限全套通俗易懂精讲(附与 Java 对比)
java·开发语言·c++
不会编程的懒洋洋2 小时前
C# P/Invoke 基础
开发语言·c++·笔记·安全·机器学习·c#·p/invoke