lundi 28 novembre 2016

Create c-wrappers for c++ objects with default instance and deduce prototypes

I have a number of C++ structs with a number of methods. The C++ structs have a "default" instance, and I would like to expose a "c" wrapper functions that uses this default instance. But I would also like to avoid repeating all the prototyles.

Alkind of C++11/14/17 and/or macro tricks are welcome, but I do not want to use code-generators.

I have something that almost works, but I'm still struggling with a few details.

// C++ class that have a "default-instance" ///////////////////////////////////
struct Foo {
    int a() { return 1; }
    int b(int) { return 2; }
    int c(int, int) { return 3; }
};

Foo *FOO = nullptr;

// emulating existing c code that can not be changed //////////////////////////
typedef int (*ptr_a_t)(int);
ptr_a_t ptr_a = nullptr;

typedef int (*ptr_b_t)(int);
ptr_b_t ptr_b = nullptr;

typedef int (*ptr_c_t)(int);
ptr_c_t ptr_c = nullptr;

// Wrapper code (almost generic) //////////////////////////////////////////////
template <typename T, T>
struct Proxy;

// Wrapper class that will use the defualt instance if initialized (FOO is
// hardcoded).
template <typename T, typename R, typename... Args, R (T::*mf)(Args...)>
struct Proxy<R (T::*)(Args...), mf> {
    static R call(Args... args) {
        if (FOO) {
//          ^^^
            return ((*FOO).*mf)(args...);
// HARD-CODED        ^^^^
        } else {
            return -1;
        }
    }
};

// Helper function to deduce the Proxy-class (method 'b' is hardcoded)
template <typename T, typename R, typename... Args>
auto deduce_args(R (T::*mf)(Args...)) -> Proxy<R (T::*)(Args...), &T::b> {
// HARD-CODED                                                         ^
    return Proxy<R (T::*)(Args...), &T::b>();
// HARD-CODED                           ^
}

// Wrap the methods ////////////////////////////////////////////////////////
//#define wrap_a decltype(deduce_args(&Foo::a))::call
#define wrap_b decltype(deduce_args(&Foo::b))::call
//#define wrap_c decltype(deduce_args(&Foo::c))::call

template <class _Fp, class... _BoundArgs>
inline void bind(_Fp &&__f, _BoundArgs &&... __bound_args) {}

int main() {
    // Test that it works
    //ptr_a = &wrap_a;  // does not work due to hard-coded method
    ptr_b = &wrap_b;
    //ptr_c = &wrap_c;  // does not work due to hard-coded method

    return ptr_b(0);
}

I can live with the hard-coded "FOO" in the proxy, as I only need one proxy per class, but it would be cool if the instance pointer could be passed as a template argument.

The hard-coded method in "deduce_args" is really anoying, how can I eliminate that??

Is there a better way to do this (the function pointers can not be replaced with std::function).

Aucun commentaire:

Enregistrer un commentaire