在函数指针返回值中转换对指针的引用

时间:2014-07-24 17:22:25

标签: c++ c++11 function-pointers emscripten

Emscripten生成自动绑定,用于从JavaScript调用C ++函数。但是,如果函数返回引用,则结果将通过值传递给JavaScript。指针返回值通过引用传递。所以,如果我有一个功能:

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

我可以做类似的事情:

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

使其显示在JavaScript中。但我需要的是:

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

使其返回指针。但是,为每个函数键入内容非常糟糕,所以我需要一个魔术宏来转换:

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

进入上面的版本(对于采用任意数量的任何类型的参数的函数),使用强制转换或类似的东西。问题是:这在C ++ 11中是否可行?

2 个答案:

答案 0 :(得分:3)

对函数指针(或成员函数指针)执行reinterpret_cast是一个非常糟糕的主意。

相反,写一个适配器:

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>())

不幸的是,因为lambda必须是无捕获的,所以必须将成员函数指针作为非类型模板参数传递,这意味着它不能被推导出来。您可以使用宏来解决此问题。

答案 1 :(得分:1)

ecatmur完美地回答了这个问题,但我花了一些时间来理解代码实际上是做什么的,所以这是一个使用宏的注释版本:

// 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())