微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

用于将 C 函数回调转发到 C++ 成员函数的 C++ thunk 类实现

如何解决用于将 C 函数回调转发到 C++ 成员函数的 C++ thunk 类实现

我尝试在 C++ 中实现一个“thunk”类,该类允许获取 C 函数指针以传递给最终调用 C++ 成员函数的 C 代码一个特定的要求是它适用于不传递 void * 上下文参数(或类似参数)的 C 代码,这在 C 代码回调中很常见。因此,必须为每个 CC++ 链接创建一个不同的全局或静态 C 粘合函数。在我的实现中,这是通过模板参数 N 实现的,对于 thunk 类的每次使用,它必须是不同的,并导致为每个模板具体化创建不同的“蹦床”函数

我的问题是:有没有一种方法可以在不需要模板参数 N 的情况下实现这一点,或者编译器可以根据某种模板“魔术”自动为每个具体化分配一个新值 N?

#ifndef THUNK_H
#define THUNK_H

#include <map>
#include <stdexcept>

template <class Sig,class Obj,size_t N>
class Thunk;

class ThunkBase
{
public:
    static void clear()
    {
        for (auto it : mThunkStorage) {
            delete it.second;
        }

        mThunkStorage.clear();
    }

    virtual ~ThunkBase() {}

protected:
    static std::map<void *,ThunkBase *> mThunkStorage;
};

template <class R,class... Args,size_t N>
class Thunk<R(*)(Args...),Obj,N> : public ThunkBase
{
public:
    Thunk(Obj &obj,R(Obj::*method)(Args...)) : mObj(obj),mMethod(method)
    {
        std::pair<decltype(mThunkStorage)::iterator,bool> resPair = mThunkStorage.emplace(
                (void *)(&Thunk<R(*)(Args...),N>::trampoline),this);

        if (!resPair.second) {
            throw std::runtime_error("Failed to insert thunk object");
        }
    }

    R(*entry())(Args...)
    {
        return &Thunk<R(*)(Args...),N>::trampoline;
    }

private:
    Obj &mObj;
    R(Obj::*mMethod)(Args...);

    static R trampoline(Args... args)
    {
        auto selfFuncPtr = &Thunk<R(*)(Args...),N>::trampoline;
    
        auto it = mThunkStorage.find((void *)selfFuncPtr);
        if (it == mThunkStorage.end()) {
            throw std::runtime_error("Could not find thunk object");
        }

        ThunkBase *base = it->second;
        Thunk<R(*)(Args...),N> *self = static_cast<Thunk<R(*)(Args...),N> *>(base);

        Obj &obj = self->mObj;
        R(Obj::*method)(Args...) = self->mMethod;
        return (obj.*method)(args...);
    }
};

#endif

std::map<void *,ThunkBase *> ThunkBase::mThunkStorage;

// -> usage would be like,for example

struct MyClass
{
    void myFunc(int);
};

MyClass myObj;
Thunk<void(*)(int),MyClass,0> myThunk(myObj,&MyClass::myFunc);
void (*myFunc)(int) = myThunk.entry();

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。