简体   繁体   English

如何将“void (MyClass::*)(int)”转换为“void (*)(int)”?

[英]How to cast “void (MyClass::*)(int)” to “void (*)(int)”?

I've looking for how to cast class member to C-style callback.我正在寻找如何将 class 成员转换为 C 样式回调。

Recentrly i found answer with special bind hack allows to bind class members to C-style callbacks:最近我找到了特殊绑定黑客的答案,允许将 class 成员绑定到 C 样式回调:

https://stackoverflow.com/a/39524069/5405443 https://stackoverflow.com/a/39524069/5405443

I have this working code to bind function MyClass::f to C function f : But i want to avoid explicit passing cb_type as template parameter to c_bind function. I have this working code to bind function MyClass::f to C function f : But i want to avoid explicit passing cb_type as template parameter to c_bind function. In provided example CB has type void (*)(int) and Func template parameter has void (MyClass::*)(int) type.在提供的示例中, CB具有void (*)(int)类型,而Func模板参数具有void (MyClass::*)(int)类型。

template<typename CB, typename Func, typename... Params>
CB* c_bind(std::_Bind<Func(Params...)> function) {
    return Callback<typename ActualType<CB>::type, __COUNTER__, Func>::getCallback(function);
}

typedef void (cb_type)(int);

class MyClass {
public:
    void f(int x) {
        std::cout << "Hello from MyClass::f(int), value: " << x << std::endl;
    }
};

int main() {
    MyClass mc;

    auto f = c_bind<cb_type>(std::bind(&MyClass::f, mc, std::placeholders::_1));
    //                ^ how to avoid explicit callback type declaration here?
    f(10);

    return 0;
}

Also i found this piece of code ( https://gist.github.com/vikchopde/73b62314379f733e8938f11b246df49c ) for "unwrapping" some kind of functions.我还发现了这段代码( https://gist.github.com/vikchopde/73b62314379f733e8938f11b246df49c )用于“展开”某种功能。

bool ok = fu::is_unwrappable<decltype(&MyClass::f)>::value; // always false
// fu::unwrap_function<decltype(&MyClass::f)>::type::function_ptr blah; // won't compile

but it won't work by unknown to me reason.但它不会以我不知道的原因起作用。

My question is there any workaround to extract return type and args list from type with class-memeber pointer like void (MyClass::*)(int) and contruct C-like type void (*)(int) ?我的问题是有什么解决方法可以从具有类成员指针(如void (MyClass::*)(int)和构造类 C 类型void (*)(int) )的类型中提取返回类型和参数列表?

Thank you for any help!感谢您的任何帮助!

Well, in C++17, you are allowed to pass an arbitrary non-type parameter to a class with template<auto> .好吧,在 C++17 中,您可以使用template<auto>将任意非类型参数传递给 class 。 Therefore, we could store MyClass::f as a template parameter and parse its type with decltype .因此,我们可以将MyClass::f存储为模板参数并使用decltype解析其类型。 After passing this type to another templated class, we are able to extract desired types using template specialization.将此类型传递给另一个模板化 class 后,我们可以使用模板特化提取所需的类型。

The code below shows how to construct a C-style function wrapper<>::func_type .下面的代码展示了如何构造一个 C 风格的 function wrapper<>::func_type

Since you seem to bind an object to its member function, I additionally write the demo code to do this by invoking wrapper<>::bind .由于您似乎将 object 绑定到其成员 function,因此我另外编写了演示代码通过调用wrapper<>::bind来执行此操作。 Hope it helps.希望能帮助到你。

class MyClass {
public:
    void f(int x) {
    std::cout << "Hello from MyClass::f(int), value: " << x << std::endl;
    }
};

void f(int x) {
    std::cout << "Hello from f(int), value: " << x << std::endl;
}

template<auto F>
struct wrapper
{
    template<typename> struct inner;

    template<class Cls, typename Ret, typename... Args>
    struct inner<Ret(Cls::*)(Args...)>
    {
        using func_type = Ret(Args...);

        static auto bind(Cls *obj)
        {
            return [=](Args ...args){
                return (obj->*F)(std::forward<Args>(args)...);
            };
        }
    };

    using func_type = typename inner<decltype(F)>::func_type;
    static const constexpr auto bind = inner<decltype(F)>::bind;
};

int main() {
    MyClass mc;

    auto h = wrapper<&MyClass::f>::bind(&mc);
    h(10);

    using func_t = typename wrapper<&MyClass::f>::func_type;
    std::function<func_t> g = f;
    g(1);
    return 0;
}

First of all i would like to thank @Dappur for nice example.首先,我要感谢@Dappur 的好例子。 Using your guide i will rewrite my ugly bind interface with std::_Bind usage later.使用您的指南,我稍后将使用 std::_Bind 使用重写我丑陋的绑定接口。 Also i want to thank @Sam Varshavchik for mentioning that set of C++ books.我还要感谢@Sam Varshavchik 提到那套 C++ 书籍。 I'll start reading it to become C++ grandmaster like you to learn how " why i cannot cast it like this ".我将开始阅读它以成为像您一样的 C++ 大师,以了解“为什么我不能像这样施放它”。 But unfortunately with my poor c++ experience I can still do it now.但不幸的是,凭借我糟糕的 c++ 经验,我现在仍然可以做到。 Here is working code:这是工作代码:

template<class T, unsigned int n, class CallerType>
struct CallbackWrapper;

template<class Ret, class... Params, unsigned int n, class CallerType>
struct CallbackWrapper<Ret(Params...), n, CallerType> {
    static auto get(std::function<Ret(Params...)>&& fn) -> Ret(*)(Params...) {
        func = fn;
        return static_cast<Ret(*)(Params...)>(CallbackWrapper<Ret(Params...), n, CallerType>::callback);
    }

private:
    static std::function<Ret(Params...)> func;

    static Ret callback(Params... args) {
        return func(args...);
    }
};

template<class Ret, class... Params, unsigned int n, class CallerType>
std::function<Ret(Params...)> CallbackWrapper<Ret(Params...), n, CallerType>::func;

template<typename T>
struct lambda_to_stdf {
    using type = void;
};

template<typename Ret, typename Class, typename... Args>
struct lambda_to_stdf<Ret(Class::*)(Args...) const> {
    using type = std::function<Ret(Args...)>;
};

template<class Ret, class Cls, class... Args1, class... Args2>
auto c_bind(std::_Bind<Ret(Cls::*(Cls, Args1...))(Args2...)> function) -> Ret(*)(Args2...) {
    return CallbackWrapper<Ret(Args2...), __COUNTER__, Ret(Cls::*(Cls, Args1...))(Args2...)>::get(std::move(function));
}

template<class Ret, class... Args>
auto c_bind(std::function<Ret(Args...)> function) -> Ret(*)(Args...) {
    return CallbackWrapper<Ret(Args...), __COUNTER__, std::function<Ret(Args...)>>::get(std::move(function));
}

template<class F>
auto c_bind(F function) -> decltype(c_bind((typename lambda_to_stdf<decltype(&F::operator())>::type)(function))) {
    return c_bind((typename lambda_to_stdf<decltype(&F::operator())>::type)(function));
}

Usage:用法:

class MyClass {
public:
    void f(int x) {
        std::cout << "Hello from MyClass::f(int), value: " << x << std::endl;
    }
};

int main() {
    MyClass mc;

    auto f = c_bind(std::bind(&MyClass::f, mc, std::placeholders::_1));
    f(10);

    std::function<void(int)> stdf = [](int v) {
        std::cout << "hello from std::function, value: " << v << std::endl;
    };
    auto f2 = c_bind(stdf);
    f2(100);

    auto f3 = c_bind([](int v) -> int {
        std::cout << "hello from lambda, value: " << v << std::endl;
        return 5.0f;
    });
    f3(1000);

    return 0;
}

Hope it will be helpful for someone.希望它对某人有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM