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

资源受限MCU下无标准库无堆分配的C++成员函数包装器实现

无reinterpret_cast的成员函数指针包装器实现(嵌入式场景适用)

该实现完全满足你的需求:仅已知返回值和参数类型即可定义包装器,无需提前感知成员函数所属类;无任何堆内存分配,所有存储内建在包装器结构体中;不依赖任何C++标准库组件;完全规避未定义行为的reinterpret_cast hack。

实现原理

采用编译期生成类型擦除跳转函数(Trampoline)的方案:

  • 用void*存储任意类的对象实例指针
  • 用对齐的字节缓冲区存储任意类型的成员函数指针
  • 针对每个传入的类类型T,编译期生成对应的静态跳转函数,负责从缓冲区取出成员函数指针完成类型安全的调用

完整可运行代码

// 无C++标准库依赖,无堆分配
#include <cstdio> // 仅用于测试打印,实际项目可移除

// 编译器无内置memcpy时可以用这个简易实现替代,无需标准库
/*
void* simple_memcpy(void* dest, const void* src, unsigned int n)
{
    char* d = static_cast<char*>(dest);
    const char* s = static_cast<const char*>(src);
    for (unsigned int i = 0; i < n; i++) d[i] = s[i];
    return dest;
}
*/

template<typename Ret, typename... Args>
struct member_cb
{
    member_cb() : obj(nullptr), trampoline(nullptr) {}

    template<typename T>
    void set_cb(T* obj_, Ret (T::*func)(Args...))
    {
        obj = static_cast<void*>(obj_);
        // 校验成员函数指针大小、对齐是否符合当前缓冲区配置
        static_assert(sizeof(func) <= sizeof(func_buf), "成员函数指针大小超出缓冲区限制");
        static_assert(alignof(decltype(func)) <= alignof(func_buf), "成员函数指针对齐要求超出缓冲区支持");
        // 嵌入式编译器普遍支持__builtin_memcpy,无需引入标准库,也可替换为上面的simple_memcpy
        __builtin_memcpy(func_buf, &func, sizeof(func));
        trampoline = &trampoline_impl<T>;
    }

    Ret operator()(Args... args)
    {
        return trampoline(obj, func_buf, args...);
    }

private:
    void* obj;
    // 16字节对齐缓冲区,足够覆盖绝大多数嵌入式平台(包括ARM Cortex-M多继承场景)的成员函数指针需求
    // 可根据实际使用平台调整大小
    alignas(alignof(void (member_cb::*)())) char func_buf[16];
    using TrampolineFunc = Ret(*)(void*, const char*, Args...);
    TrampolineFunc trampoline;

    // 针对每个类类型T在编译期生成专属跳转实现
    template<typename T>
    static Ret trampoline_impl(void* obj_ptr, const char* func_buf_ptr, Args... args)
    {
        Ret (T::*func)(Args...);
        __builtin_memcpy(&func, func_buf_ptr, sizeof(func));
        T* instance = static_cast<T*>(obj_ptr);
        return (instance->*func)(args...);
    }
};

// 测试用例
struct Bar{
    void someFunc(int n2){
        printf("someFunc called with parameter: %d\n",n2);
    }
};

int main()
{
    member_cb<void, int> foo;
    Bar bar;
    foo.set_cb(&bar, &Bar::someFunc);
    foo(42);
    return 0;
}

实现说明

  • 运行效率极高,仅多一次函数跳转开销,和你最初的reinterpret_cast版本性能几乎一致
  • 所有类型转换都是C++标准允许的静态转换,无任何未定义行为,兼容性远优于hack实现
  • 缓冲区大小可根据实际使用平台灵活调整,32位ARM平台8字节即可覆盖绝大多数场景,16字节可覆盖所有多继承、虚继承场景

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 06:09:02