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

Posted

技术标签:

【中文标题】在函数指针返回值中转换对指针的引用【英文标题】:Cast reference to pointer in function pointer return value 【发布时间】:2014-07-24 17:22:25 【问题描述】:

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 中可行吗?

【问题讨论】:

我无法理解reinterpret_cast。它是如何工作的,甚至是如何工作的? 它将 MyType &MyClass::doStuff 声明中的第一个 & 更改为 *。 我很确定使用reinterpret_cast 通过指向不同类型函数的指针调用函数是未定义的行为。 这是特定于 emscripten 编译器的,所以如果它是不可移植的也没关系。并且假装一个引用是一个指针听起来并不那么糟糕...... 【参考方案1】:

在函数指针(或成员函数指针)上执行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 必须是无捕获的,所以成员函数指针必须作为非类型模板参数传递,这意味着它不能被推导。您可以使用宏来解决此问题。

【讨论】:

谢谢!我怀疑会有比演员更清洁的方式,但不知道怎么做。这非常有效。【参考方案2】:

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

【讨论】:

以上是关于在函数指针返回值中转换对指针的引用的主要内容,如果未能解决你的问题,请参考以下文章

使用引用向下转换非指针

通过引用返回指针数组

C++ - 返回指针或常量引用

将c ++引用的地址传递给指针

用“void*”转换“char”指针并取消引用它

函数可以返回一个局部对象,而不能返回一个局部对象的引用(指针):