C++0x实践:function结合bind巧封装回调函数
很喜欢function,但之前没认真思考,总感觉在使用bind绑定时很麻烦,所以有抵触情绪,有时宁可使用函数指针或thunk。今天又想起这个问题,并且尝试了一下将bind部分封装到类里:如能实现,外部接口只需要将需要回调的函数名传递进去即可。
经过一番努力,使用模板类实现了。
主要代码:
- C/C++ code
namespace qp{class Search{public: Search() : m_func(NULL) {} template <typename T1, typename T2> void RegisterNotify(T1 memberFunc, T2* pThis) { m_func = std::bind(memberFunc, pThis, std::placeholders::_1, std::placeholders::_2); } template <typename T> void RegisterNotify(T globalFunc) { m_func = std::bind(globalFunc, std::placeholders::_1, std::placeholders::_2); } bool Run() { if (m_func != NULL) return m_func(_T("Hello World!"), NULL); return false; }private: typedef std::function<bool (qp::String fileOrPath, void* pUserData)> NotifyFunc; NotifyFunc m_func;};} // namespace qp
- C/C++ code
class A{public: A() { ss.RegisterNotify(&A::SearchFiles, this); ss.Run(); } bool SearchFiles(qp::String fileOrPath, void* pUserData) { std::cout << pUserData << fileOrPath << std::endl; return true; }private: qp::Search ss;};bool SearchFiles(qp::String fileOrPath, void* pUserData){ std::cout << "SearchFiles\n"; return true;}int _tmain(int argc, TCHAR* argv[]){ A a; qp::Search ss; ss.RegisterNotify(&SearchFiles); ss.Run(); return 0;}
其中,qp::String可以替换成std::string。
总体来看,接口是简洁好用的,用户只需要调用RegisterNotify注册回调函数。
请用VS2008SP1以上、MinGW 4.4以上编译器编译。
[解决办法]
感觉还行吧, 给一个可以在VS2010上跑的版本
- C/C++ code
#include <iostream>#include<vector> #include<algorithm> #include <functional>#include <string>using namespace std; using namespace std::tr1;namespace qp{class Search{public: Search() : m_func(NULL) {} template <typename T1, typename T2> void RegisterNotify(T1 memberFunc, T2* pThis) { m_func = std::bind(memberFunc, pThis, std::placeholders::_1, std::placeholders::_2); } template <typename T> void RegisterNotify(T globalFunc) { m_func = std::bind(globalFunc, std::placeholders::_1, std::placeholders::_2); } bool Run() { if (m_func != NULL) return m_func(string("Hello World!"), NULL); return false; }private: typedef std::function<bool (std::string fileOrPath, void* pUserData)> NotifyFunc; NotifyFunc m_func;};} // namespace qpclass A{public: A() { ss.RegisterNotify(&A::SearchFiles, this); ss.Run(); } bool SearchFiles(string fileOrPath, void* pUserData) { std::cout << pUserData << fileOrPath << std::endl; return true; }private: qp::Search ss;};bool SearchFiles(string fileOrPath, void* pUserData){ std::cout << "SearchFiles\n"; return true;}int _tmain(int argc, _TCHAR* argv[]){ A a; qp::Search ss; ss.RegisterNotify(&SearchFiles); ss.Run(); return 0;}
[解决办法]
把楼主的搜索函数改了一下,不知道楼主有何见解:
- C/C++ code
void Search:: DoFileEnumeration(const qp::String strPath, bool bRecursion, bool bEnumFiles, void* pUserData) { try { if (m_bUserBreak) return; WIN32_FIND_DATA fd; HANDLE hFindFile = ::FindFirstFile(qp::Path::Append(strPath, _T("*")).c_str(), &fd); if (hFindFile == INVALID_HANDLE_VALUE) { ::FindClose(hFindFile); return; } do { const qp::String fileName(fd.cFileName); qp::String tmpPath = qp::Path::Append(strPath, fileName); if (isDirectory && (fileName == _T(".") || fileName == _T(".."))) { continue; } if (bEnumFiles != isDirectory) { qpASSERT(m_func); if (m_func && m_func(tmpPath, pUserData) == false) { m_bUserBreak = true; ::FindClose(hFindFile); return; } } if (isDirectory && bRecursion) { DoFileEnumeration(tmpPath, bRecursion, bEnumFiles, pUserData); } } while(::FindNextFile(hFindFile, &fd)); ::FindClose(hFindFile); } catch (...) { qpASSERT(false); qp::Debug::OutputString(_T("qp::Search's DoFileEnumeration throw Exception.")); return; } }