【问题标题】:Calling Rcpp function with Xptr and Function - only xptr case works使用 Xptr 和 Function 调用 Rcpp 函数 - 只有 xptr 案例有效
【发布时间】:2018-07-10 21:51:04
【问题描述】:

我正在尝试开发一个包,我需要在其中输入来自用户的函数(可以使用RcppR 定义),将其发送到struct 中的另一个函数(在包内)并在那里处理它。

当我使用Rcpp::Xptr(即函数指针)时,代码可以工作,但同样不能用于Rcpp::Function。为用户使用Rcpp::Function 的好处是他们可以在R 中定义函数(尽管会损失很多性能增益)。

首先什么是有效的:

#include <Rcpp.h>
using namespace Rcpp;

// define the structure
struct xptr_data{
  SEXP xptr;
};

// a minimal function (user-defined)
// [[Rcpp::export]]
NumericVector timesTwo(NumericVector x) {
  return x * 2;
}

// pointer to function defined
typedef NumericVector (*funcPtr) (NumericVector y);

// [[Rcpp::export]]
XPtr<funcPtr> putFunPtrInXPtr() {

  XPtr<funcPtr> rhs_ptr(new funcPtr(&timesTwo), false); 
  return rhs_ptr;
}

// this function will be in the package
NumericVector call_by_xptr_struct(NumericVector y, void* user_data){

  struct xptr_data *my_rhs_ptr = (struct xptr_data*)user_data;
  SEXP xpsexp = (*my_rhs_ptr).xptr;

  // use function pointer to get the derivatives
  XPtr<funcPtr> rhs_xptr(xpsexp);
  funcPtr rhs_fun = *rhs_xptr;

  // use the function to calculate value of RHS ----
  return(rhs_fun(y));
}


// using xptr to evaluate function - this will be exported
// from the package
//[[Rcpp::export]]
NumericVector xptr_call_struct(NumericVector y, SEXP xpsexp){

  struct xptr_data my_xptr = {NULL};

  my_xptr.xptr = xpsexp;
  return call_by_xptr_struct(y, (void*)&my_xptr);
}

/*** R    
rhs_ptr <- putFunPtrInXPtr()

xptr_call_struct(c(1,2), rhs_ptr)
[1] 2 4
*/ 

什么是行不通的,

如果函数在R中定义,而我直接使用Rcpp::Function,它会导致整个R会话崩溃,

#include <Rcpp.h>
using namespace Rcpp;

// define the function based structure
struct func_data{
  Function func;
};

// processes the input function 
NumericVector call_by_func_struct(NumericVector y, void* user_data){

  struct func_data *my_rhs_fun = (struct func_data*)user_data;
  Function func = (*my_rhs_fun).func;

  return(func(y));
}

// this will be exported from the package
//[[Rcpp::export]]
NumericVector func_call_struct(NumericVector y, Function func){

  struct func_data my_func = {NULL};

  my_func.func = func;
  return call_by_func_struct(y, (void*)&my_func);
}

/*** R
timesThree <- function(y){

  y <- 3 * y
  y
}

*/

上面的代码编译得很好,但是当我调用函数 func_call_struct(c(1,2), timesThree)) 时,它会导致整个 R 会话崩溃。

任何关于为什么R 崩溃以及如何输入R 中定义的函数的指导都会非常有帮助。

此外,有没有办法传递Rcpp 中定义的输入函数(例如,上面的timesTwo)而不是它们的Xptr。我认为在不牺牲Rcpp 带来的速度的情况下,最终用户的困惑会稍微少一些(因为他们不必生成函数指针)。

【问题讨论】:

    标签: r rcpp r-package


    【解决方案1】:

    如果你 initialize the struct 使用可用的 Function,它会起作用:

    [...]
    // this will be exported from the package
    //[[Rcpp::export]]
    NumericVector func_call_struct(NumericVector y, Function func){
    
      struct func_data my_func = {func};
      return call_by_func_struct(y, (void*)&my_func);
    }
    

    至于您的附加问题:我看不到在不使用外部指针的情况下将 C++ 函数指针存储在 R 中的可能性。你不能提供一个从函数指针创建外部指针的辅助函数(可能是wrap())吗?大致如下:

    #include <Rcpp.h>
    using namespace Rcpp;
    
    // define the structure
    struct xptr_data{
      SEXP xptr;
    };
    
    // pointer to function defined
    typedef NumericVector (*funcPtr) (NumericVector y);
    
    
    // this function will be in the package
    NumericVector call_by_xptr_struct(NumericVector y, void* user_data){
    
      struct xptr_data *my_rhs_ptr = (struct xptr_data*)user_data;
      SEXP xpsexp = (*my_rhs_ptr).xptr;
    
      // use function pointer to get the derivatives
      XPtr<funcPtr> rhs_xptr(xpsexp);
      funcPtr rhs_fun = *rhs_xptr;
    
      // use the function to calculate value of RHS ----
      return(rhs_fun(y));
    }
    
    
    // using xptr to evaluate function - this will be exported
    // from the package
    //[[Rcpp::export]]
    NumericVector xptr_call_struct(NumericVector y, SEXP xpsexp){
    
      struct xptr_data my_xptr = {xpsexp};
      return call_by_xptr_struct(y, (void*)&my_xptr);
    }
    
    
    // function in package with only C++ API
    XPtr<funcPtr> wrapFunPtr(funcPtr& f) {
      XPtr<funcPtr> rhs_ptr(&f, false); 
      return rhs_ptr;
    }
    
    
    
    // user-defined functions
    NumericVector timesTwo(NumericVector x) {
      return x * 2;
    }
    
    // [[Rcpp::export]]
    XPtr<funcPtr> putFunPtrInXPtr() {
      static funcPtr f = &timesTwo;
      return wrapFunPtr(f);
    }
    
    
    
    /*** R    
    rhs_ptr <- putFunPtrInXPtr()
    
    xptr_call_struct(c(1,2), rhs_ptr)
    */ 
    

    用户将提供最后两个函数。使用 C++11 可以这样简化:

    // [[Rcpp::export]]
    XPtr<funcPtr> putFunPtrInXPtr() {
      static funcPtr timesTwo{ [](NumericVector x) -> NumericVector { return x * 2; } };
      return wrapFunPtr(timesTwo); 
    }
    

    虽然在这种情况下使用它可能就足够了

    // [[Rcpp::export]]
    XPtr<funcPtr> putFunPtrInXPtr() {
      static funcPtr timesTwo{ [](NumericVector x) -> NumericVector { return x * 2; } };
      XPtr<funcPtr> rhs_ptr(timesTwo, false); 
      return rhs_ptr;
    }
    

    在包中不需要wrapFunPtr。用户必须提供一个函数,其中包括一些样板代码以及 lambda 表达式中的实际“肉”。

    【讨论】:

    • 感谢您的快速回复!!对于附加问题,我需要用户定义函数的确切名称来创建函数指针(即'&NameOfUserDefinedFunction'),这是不可能的。你能提供一个最小的例子来说明你的想法吗?谢谢!!
    • 再次感谢您的全面回答,我将尝试了解其工作原理并尝试实施!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-01
    • 2013-11-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多