如何为任意成员函数编写通用非成员包装器?
解决成员函数包装器编译错误的思路
你的问题根源很明确:你试图返回一个依赖非类型模板参数的模板函数地址,但你的staticWrapper是普通函数,没办法把传入的成员函数指针绑定到模板参数上。模板函数wrapper必须拿到具体的成员函数指针作为模板参数,才能实例化出一个可作为普通函数指针传递的非模板静态函数,而你当前的实现没做到这一点。
下面是修正后的完整实现,同时支持const和非const成员函数,且完全满足“包装器不是lambda、可作为函数指针传递”的要求:
#include <iostream> #include <string> #include <tuple> #include <type_traits> // 自定义类型萃取工具,用于解析成员函数指针的类型信息 template<typename T> struct member_function_traits; // 处理非const成员函数 template<typename Class, typename R, typename... Args> struct member_function_traits<R (Class::*)(Args...)> { using class_type = Class; using return_type = R; using args_tuple = std::tuple<Args...>; template<std::size_t N> using arg_type = std::tuple_element_t<N, args_tuple>; }; // 处理const成员函数 template<typename Class, typename R, typename... Args> struct member_function_traits<R (Class::*)(Args...) const> { using class_type = Class; using return_type = R; using args_tuple = std::tuple<Args...>; template<std::size_t N> using arg_type = std::tuple_element_t<N, args_tuple>; }; // 非const成员函数的包装器Helper template<typename Traits, auto Func> struct member_wrapper_impl; template<typename Class, typename R, typename... Args, R (Class::*Func)(Args...)> struct member_wrapper_impl<member_function_traits<R (Class::*)(Args...)>, Func> { static R wrapper(Class& obj, Args... args) { return (obj.*Func)(std::forward<Args>(args)...); } }; // const成员函数的包装器Helper template<typename Class, typename R, typename... Args, R (Class::*Func)(Args...) const> struct member_wrapper_impl<member_function_traits<R (Class::*)(Args...) const>, Func> { static R wrapper(const Class& obj, Args... args) { return (obj.*Func)(std::forward<Args>(args)...); } }; // C++17及以上版本:用auto非类型模板参数简化调用 template<auto Func> constexpr auto make_member_wrapper = &member_wrapper_impl< member_function_traits<decltype(Func)>, Func >::wrapper; // C++14兼容版本:通过函数参数推导模板参数 template<typename T> constexpr auto make_member_wrapper(T Func) { return &member_wrapper_impl< member_function_traits<T>, Func >::wrapper; } // 测试示例 class A { public: void print() { std::cout << "A::print called\n"; } int sum(int a, int b) { return a + b; } }; int main() { // 测试非const成员函数(C++17调用方式) auto a_print_wrapper = make_member_wrapper<&A::print>; A a; a_print_wrapper(a); // 输出 "A::print called" auto a_sum_wrapper = make_member_wrapper<&A::sum>; std::cout << a_sum_wrapper(a, 4, 6) << "\n"; // 输出 10 // 测试const成员函数(C++14调用方式) auto string_empty_wrapper = make_member_wrapper(&std::string::empty); const std::string non_empty = "test"; std::cout << std::boolalpha << string_empty_wrapper(non_empty) << "\n"; // 输出 false const std::string empty_str; std::cout << string_empty_wrapper(empty_str) << "\n"; // 输出 true return 0; }
关键修正点说明
- 用非类型模板参数绑定成员函数:把成员函数指针作为模板参数传递给
member_wrapper_impl,这样wrapper就能绑定到具体的成员函数,实例化出一个非模板的静态函数,它的地址可以直接作为普通函数指针返回。 - 区分const/非const成员函数:通过重载
member_wrapper_impl和自定义类型萃取工具,分别处理对象是Class&还是const Class&的情况。 - 简化调用体验:提供C17和C14两种调用方式,前者借助
auto非类型模板参数,调用时只需传入&Class::member;后者通过函数参数自动推导类型。 - 完美转发参数:使用
std::forward保证参数传递的正确性,避免不必要的拷贝。
内容的提问来源于stack exchange,提问作者haku
相关产品推荐
相关产品推荐

