C++中BinarySearchTree遍历传递Vector成员函数报错求助
问题描述
我实现了模板类BinarySearchTree的InorderTraversal方法,该方法接收函数指针travPtr<T>作为回调参数用于遍历树节点。尝试将BST中存储的Weather类型数据,通过Vector类的Add成员函数存入Vector<Weather>对象tempMap中时,调用(it->second).InorderTraversal(tempMap.Add)出现编译错误:
no matching function for call to 'BinarySearchTree
::InorderTraversal( )'
但传递全局模板函数Print时该方法可正常运行,寻求错误解决办法。
错误根源
成员函数和普通全局函数的签名本质不同:成员函数隐含一个this指针作为第一个参数,而InorderTraversal期望的是不带隐式参数的普通函数指针。直接传递tempMap.Add时,编译器无法将带隐式this的成员函数签名,匹配到要求的普通函数指针类型,因此报错。
可行解决方案
1. 使用Lambda表达式包装成员函数
Lambda可以捕获目标对象,在内部直接调用成员函数,其签名可以完美匹配InorderTraversal要求的函数指针:
(it->second).InorderTraversal([&tempMap](const Weather& data) { tempMap.Add(data); });
如果InorderTraversal的函数指针要求参数是T而非const T&,只需调整Lambda的参数类型即可。
2. 用std::bind绑定成员函数与对象
通过std::bind将tempMap的地址(即this指针)绑定到Add成员函数上,生成适配普通函数指针的可调用对象:
#include <functional> // 假设travPtr<T>的签名为void(*)(const T&) auto bound_add = std::bind(&Vector<Weather>::Add, &tempMap, std::placeholders::_1); (it->second).InorderTraversal(bound_add);
注意需包含<functional>头文件,若bind生成的对象无法隐式转换为目标函数指针,需结合方法3调整参数类型。
3. 修改InorderTraversal的参数类型为std::function
如果有权修改BinarySearchTree的代码,将函数指针参数替换为std::function,可以兼容普通函数、Lambda、绑定后的成员函数等所有可调用对象,灵活性拉满:
#include <functional> template<typename T> class BinarySearchTree { public: void InorderTraversal(std::function<void(const T&)> callback) { // 遍历逻辑中调用 callback(node->data) } };
修改后直接使用Lambda或bind的调用方式即可正常运行,无需再纠结函数指针的匹配问题。
4. 编写全局包装函数(兼容旧代码)
若无法修改InorderTraversal的参数类型,可写一个全局模板函数作为中间层,接收容器指针和数据后调用成员函数:
template<typename T> void AddToVector(Vector<T>* vec, const T& data) { vec->Add(data); }
调用时通过Lambda或bind传递包装函数:
// Lambda方式 (it->second).InorderTraversal([](const Weather& data) { AddToVector(&tempMap, data); }); // bind方式 auto bound_func = std::bind(AddToVector<Weather>, &tempMap, std::placeholders::_1); (it->second).InorderTraversal(bound_func);
内容的提问来源于stack exchange,提问作者Aloysious Kok

