You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为任意成员函数编写通用非成员包装器?

解决成员函数包装器编译错误的思路

你的问题根源很明确:你试图返回一个依赖非类型模板参数的模板函数地址,但你的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;
}

关键修正点说明

  1. 用非类型模板参数绑定成员函数:把成员函数指针作为模板参数传递给member_wrapper_impl,这样wrapper就能绑定到具体的成员函数,实例化出一个非模板的静态函数,它的地址可以直接作为普通函数指针返回。
  2. 区分const/非const成员函数:通过重载member_wrapper_impl和自定义类型萃取工具,分别处理对象是Class&还是const Class&的情况。
  3. 简化调用体验:提供C17和C14两种调用方式,前者借助auto非类型模板参数,调用时只需传入&Class::member;后者通过函数参数自动推导类型。
  4. 完美转发参数:使用std::forward保证参数传递的正确性,避免不必要的拷贝。

内容的提问来源于stack exchange,提问作者haku

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 15:02:43