如何正确编写C++类成员函数包装器?解决编译报错问题
如何正确包装重载的类成员函数,实现执行前后的准备与清理操作
看起来你遇到的核心问题是重载成员函数的模板参数推导失败,还有一些小的语法细节需要修正。我来一步步帮你解决:
为什么会编译报错?
当你尝试写a.wrapper(a.c, 1, "abc")时,有几个关键问题导致了编译失败:
- 重载函数的歧义:
A::c有两个重载版本(bool c(int, string)和string c(string)),编译器没办法自动推断你要传递的是哪一个,导致模板参数F无法推导。 - 成员函数的传递方式错误:成员函数不能直接用
a.c这种方式传递,正确的成员函数指针写法是&A::c。 - 运算符优先级问题:原代码里的
cout << ... ? "successful" : "fail"会因为<<的优先级高于?:导致语法错误,需要给三目表达式加括号。 - 返回值缺失:你的
c和r成员函数声明了返回值但没有实际返回语句,这也会触发编译错误。
解决方案
我给你提供几种可行的实现方式,从简单直观到优雅灵活:
方法1:显式指定重载版本(强制转换成员函数指针)
直接通过强制转换明确成员函数指针的类型,告诉编译器你要调用的是哪个重载版本:
#include <iostream> #include <string> #include <utility> // 用于std::forward using namespace std; class A { public: void connect() {}; void close() {}; template<typename F, typename ... Args> auto wrapper(F&& f, Args&& ... args) -> typename std::result_of<F(Args...)>::type { using return_type = typename std::result_of<F(Args...)>::type; connect(); return_type ret = std::forward<F>(f)(std::forward<Args>(args)...); // 保持完美转发 close(); return ret; } bool c(int a, string b) { return true; } // 补充返回值 string c(string b) {return b;} bool r(int a, string b) { return true; } // 补充返回值 }; int main() { A a; // 调用bool版本的c bool res1 = a.wrapper(static_cast<bool(A::*)(int, string)>(&A::c), 1, "abc"); cout << "result of a is: " << (res1 ? "successful" : "fail") << endl; // 给三目表达式加括号 // 调用string版本的c string res2 = a.wrapper(static_cast<string(A::*)(string)>(&A::c), "abc"); cout << "result of another a is: " << res2 << endl; // 调用r函数 bool res3 = a.wrapper(static_cast<bool(A::*)(int, string)>(&A::r), 1, "abc"); cout << "result of r is:" << (res3 ? "successful" : "fail") << endl; }
方法2:使用Lambda表达式(更简洁直观)
用Lambda捕获当前对象,直接在Lambda里调用成员函数,这样编译器能明确知道调用的是哪个重载版本,代码可读性更好:
#include <iostream> #include <string> #include <utility> using namespace std; class A { public: void connect() {}; void close() {}; template<typename F, typename ... Args> auto wrapper(F&& f, Args&& ... args) -> typename std::result_of<F(Args...)>::type { connect(); auto ret = std::forward<F>(f)(std::forward<Args>(args)...); close(); return ret; } bool c(int a, string b) { return true; } string c(string b) {return b;} bool r(int a, string b) { return true; } }; int main() { A a; // 调用bool版本的c bool res1 = a.wrapper([&a](int x, string s) { return a.c(x, s); }, 1, "abc"); cout << "result of a is: " << (res1 ? "successful" : "fail") << endl; // 调用string版本的c string res2 = a.wrapper([&a](string s) { return a.c(s); }, "abc"); cout << "result of another a is: " << res2 << endl; // 调用r函数 bool res3 = a.wrapper([&a](int x, string s) { return a.r(x, s); }, 1, "abc"); cout << "result of r is:" << (res3 ? "successful" : "fail") << endl; }
方法3:重载wrapper函数,专门支持成员函数(最优雅)
给wrapper增加一个重载版本,专门处理成员函数指针,这样调用时可以直接传&A::c,编译器会根据后续参数自动匹配重载:
#include <iostream> #include <string> #include <utility> using namespace std; class A { public: void connect() {}; void close() {}; // 处理普通函数、Lambda等可调用对象的版本 template<typename F, typename ... Args> auto wrapper(F&& f, Args&& ... args) { connect(); auto ret = std::forward<F>(f)(std::forward<Args>(args)...); close(); return ret; } // 专门处理成员函数指针的版本 template<typename R, typename... MemberArgs, typename... Args> R wrapper(R(A::*mem_func)(MemberArgs...), Args&&... args) { connect(); R ret = (this->*mem_func)(std::forward<Args>(args)...); close(); return ret; } bool c(int a, string b) { return true; } string c(string b) {return b;} bool r(int a, string b) { return true; } }; int main() { A a; // 自动匹配bool版本的c bool res1 = a.wrapper(&A::c, 1, "abc"); cout << "result of a is: " << (res1 ? "successful" : "fail") << endl; // 自动匹配string版本的c string res2 = a.wrapper(&A::c, "abc"); cout << "result of another a is: " << res2 << endl; // 调用r函数 bool res3 = a.wrapper(&A::r, 1, "abc"); cout << "result of r is:" << (res3 ? "successful" : "fail") << endl; }
额外优化建议
- 如果你的编译器支持C++14及以上,可以用
auto直接推导wrapper的返回值,不需要std::result_of,代码更简洁。 - C++17里
std::result_of已经被弃用,推荐使用std::invoke_result替代。 - 始终用
std::forward保持参数的完美转发,避免不必要的拷贝。
内容的提问来源于stack exchange,提问作者Liu Weibo
相关产品推荐
相关产品推荐

