简体   繁体   中英

Cast reference to pointer in function pointer return value

Emscripten generates automatic bindings for calling C++ functions from JavaScript. However if the function returns a reference, the result gets passed by value to JavaScript. Pointer return values are passed by reference. So if I have a function:

MyType &MyClass::doStuff(int x,int y);

I can do something like:

function("doStuff",&MyClass::doStuff);

to make it appear in JavaScript. But what I need is:

function("doStuff",reinterpret_cast<MyType *(MyClass::*)(int,int)>(&doStuff));

to make it return a pointer. However that's awful to type for each function so I'd need a magic macro to convert:

function("doStuff",MAGIC(MyClass::doStuff));

into the version above (for functions taking any number of any type of arguments) with a cast, or something equivalent. Question is: Is this possible in C++11?

Performing a reinterpret_cast on a function pointer (or a member function pointer) is a seriously bad idea.

Instead, write an adaptor:

template<typename M, M m> struct make_wrapper_helper;
template<typename T, typename R, typename... A, R& (T::*m)(A...)>
struct make_wrapper_helper<R& (T::*)(A...), m> {
  R* (*operator()())(T&, A...) {
    return [](T& t, A ...a) -> R* { return &(t.*m)(static_cast<A>(a)...); };
  }
};
template<typename M, M m>
decltype(make_wrapper_helper<M, m>()()) make_wrapper() {
  return make_wrapper_helper<M, m>()();
}

function("doStuff", make_wrapper<decltype(&MyClass::doStuff), &MyClass::doStuff>())

Unfortunately, because the lambda has to be captureless, the member function pointer has to be passed as a non-type template parameter, which means it can't be deduced. You can use a macro to work around this.

ecatmur answered the question perfectly, but it took me some time to understand what the code actually does so here's a commented version using a macro:

// Helper type for PTR_RETURN() macro.
template<typename RetTypeRef, RetTypeRef method> struct ptrReturnHelper;
// Specialize the helper for a particular class, method and set of arguments.
template<
    typename Class,
    typename RetType,
    typename... ArgType,
    RetType &(Class::*method)(ArgType...)
> struct ptrReturnHelper<RetType &(Class::*)(ArgType...), method> {
    /* Function returning function pointer,
       called inside EMSCRIPTEN_BINDINGS block. */
    auto getWrapper()->auto(*)(Class &, ArgType...)->RetType * {
        /* PTR_RETURN() macro ultimately returns this lambda function which
           converts the original function pointer return value: */
        return [](Class &obj, ArgType ...arg) -> RetType * {
            return &(obj.*method)(static_cast<ArgType>(arg)...);
        };
    }
};

/* Convert a pointer to RetType &Class::method(ArgType...)
   into a pointer to    RetType *Class::method(ArgType...) */
#define PTR_RETURN(method) \
    (ptrReturnHelper<decltype(method),method>().getWrapper())

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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