使用 Xptr 和 Function 调用 Rcpp 函数 - 仅适用于 xptr 案例 [英] Calling Rcpp function with Xptr and Function - only xptr case works
问题描述
我正在尝试开发一个包,我需要在其中输入用户的函数(可以使用 Rcpp
或在 R
中定义),将其发送到另一个函数(在包内)在 struct
中并在那里处理它.
当我使用 Rcpp::Xptr
(即函数指针)时,代码有效,但同样不适用于 Rcpp::Function
.为用户使用 Rcpp::Function
的好处是他们可以在 R
中定义函数(尽管会损失很多性能增益).>
首先是什么:
#include 使用命名空间 Rcpp;//定义结构结构 xptr_data{SEXP xptr;};//一个最小函数(用户定义)//[[Rcpp::export]]NumericVector timesTwo(NumericVector x) {返回 x * 2;}//指向已定义函数的指针typedef NumericVector (*funcPtr) (NumericVector y);//[[Rcpp::export]]XPtr<funcPtr>putFunPtrInXPtr() {XPtr<funcPtr>rhs_ptr(new funcPtr(×Two), false);返回 rhs_ptr;}//这个函数会在包里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;//使用函数指针获取导数XPtr<funcPtr>rhs_xptr(xpsexp);funcPtr rhs_fun = *rhs_xptr;//使用函数计算 RHS 的值 ----返回(rhs_fun(y));}//使用 xptr 来评估函数 - 这将被导出//从包//[[Rcpp::export]]NumericVector xptr_call_struct(NumericVector y, SEXP xpsexp){struct xptr_data my_xptr = {NULL};my_xptr.xptr = xpsexp;返回 call_by_xptr_struct(y, (void*)&my_xptr);}/*** Rrhs_ptr <- putFunPtrInXPtr()xptr_call_struct(c(1,2), rhs_ptr)[1] 2 4*/
什么不起作用,
如果函数是在 R
中定义的,而我直接使用 Rcpp::Function
,它会导致整个 R 会话崩溃,
#include 使用命名空间 Rcpp;//定义基于函数的结构结构函数数据{函数 func;};//处理输入函数NumericVector call_by_func_struct(NumericVector y, void* user_data){struct func_data *my_rhs_fun = (struct func_data*)user_data;函数 func = (*my_rhs_fun).func;返回(功能(y));}//这将从包中导出//[[Rcpp::export]]NumericVector func_call_struct(NumericVector y, 函数函数){struct func_data my_func = {NULL};my_func.func = func;return call_by_func_struct(y, (void*)&my_func);}/*** RtimesThree <- 函数(y){y <- 3 * y是}*/
上面的代码编译得很好,但是当我调用函数 func_call_struct(c(1,2), timesThree))
时,它会导致整个 R 会话崩溃.
任何关于 R
崩溃的原因以及如何输入 R
中定义的函数的指导都会非常有帮助.
此外,有没有办法传递Rcpp
(例如上面的timesTwo
)中定义的输入函数,而不是它们的Xptr
.我认为在不牺牲 Rcpp
带来的速度的情况下,这对最终用户来说会稍微减少一些混乱(因为他们不必生成函数指针).
<代码>[...]//这将从包中导出//[[Rcpp::export]]NumericVector func_call_struct(NumericVector y, 函数函数){struct func_data my_func = {func};return call_by_func_struct(y, (void*)&my_func);}
至于您的附加问题:我看不到在不使用外部指针的情况下在 R 中存储 C++ 函数指针的可能性.你不能提供一个从函数指针创建外部指针的辅助函数(可能是 wrap()
)吗?一些类似的东西:
#include 使用命名空间 Rcpp;//定义结构结构 xptr_data{SEXP xptr;};//指向已定义函数的指针typedef NumericVector (*funcPtr) (NumericVector y);//这个函数会在包里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;//使用函数指针获取导数XPtr<funcPtr>rhs_xptr(xpsexp);funcPtr rhs_fun = *rhs_xptr;//使用函数计算 RHS 的值 ----返回(rhs_fun(y));}//使用 xptr 来评估函数 - 这将被导出//从包//[[Rcpp::export]]NumericVector xptr_call_struct(NumericVector y, SEXP xpsexp){struct xptr_data my_xptr = {xpsexp};返回 call_by_xptr_struct(y, (void*)&my_xptr);}//包中的函数,只有 C++ APIXPtr<funcPtr>wrapFunPtr(funcPtr& f) {XPtr<funcPtr>rhs_ptr(&f, false);返回 rhs_ptr;}//用户自定义函数NumericVector timesTwo(NumericVector x) {返回 x * 2;}//[[Rcpp::export]]XPtr<funcPtr>putFunPtrInXPtr() {静态 funcPtr f = ×Two;返回 wrapFunPtr(f);}/*** Rrhs_ptr <- putFunPtrInXPtr()xptr_call_struct(c(1,2), rhs_ptr)*/
用户将提供最后两个函数.使用 C++11,这可以简化如下:
//[[Rcpp::export]]XPtr<funcPtr>putFunPtrInXPtr() {静态 funcPtr timesTwo{ [](NumericVector x) ->NumericVector { 返回 x * 2;} };返回 wrapFunPtr(timesTwo);}
虽然在这种情况下使用可能就足够了
//[[Rcpp::export]]XPtr<funcPtr>putFunPtrInXPtr() {静态 funcPtr timesTwo{ [](NumericVector x) ->NumericVector { 返回 x * 2;} };XPtr<funcPtr>rhs_ptr(timesTwo, false);返回 rhs_ptr;}
不需要包中的 wrapFunPtr
.用户必须提供一个函数,其中包括一些样板代码以及 lambda 表达式中的实际肉".
I am trying to develop a package in which I need to input a function from user (could be defined using Rcpp
or in R
), send it to another function (within the package) in a struct
and process it there.
When I use Rcpp::Xptr
(i.e., function pointer) the code works, but the same does not work with Rcpp::Function
. The advantage with using Rcpp::Function
for the user would be that they would be able to define the function in R
(although lose a lot of performance gain).
First what works:
#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(×Two), 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
*/
What doesn't work,
If the function is defined in R
and I use Rcpp::Function
directly, it crashes the entire R session,
#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
}
*/
The code above compiles fine, but when I call the function func_call_struct(c(1,2), timesThree))
, it crashes entire R session.
Any guidance regarding why R
is crashing and how to input functions defined in R
would be very helpful.
Additionally, is there any way to pass input functions defined in Rcpp
(e.g., timesTwo
above) and not their Xptr
. I am thinking that would be slightly less confusing for the end-user (as they won't have to generate a function pointer) without sacrificing the speed that comes with Rcpp
.
It works if you initialize the struct using the available 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);
}
As for your additional question: I do not see a possibility to store a C++ function pointer within R without using an external pointer. Can't you provide a helper function (possibly as wrap()
) that creates the external pointer from the function pointer? Something along these lines:
#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 = ×Two;
return wrapFunPtr(f);
}
/*** R
rhs_ptr <- putFunPtrInXPtr()
xptr_call_struct(c(1,2), rhs_ptr)
*/
The user would supply the last two functions. With C++11 this could be simplified like this:
// [[Rcpp::export]]
XPtr<funcPtr> putFunPtrInXPtr() {
static funcPtr timesTwo{ [](NumericVector x) -> NumericVector { return x * 2; } };
return wrapFunPtr(timesTwo);
}
Although in this case it might be sufficient to use
// [[Rcpp::export]]
XPtr<funcPtr> putFunPtrInXPtr() {
static funcPtr timesTwo{ [](NumericVector x) -> NumericVector { return x * 2; } };
XPtr<funcPtr> rhs_ptr(timesTwo, false);
return rhs_ptr;
}
without the need for wrapFunPtr
in the package. The user has to supply one function, which includes some boiler-plate code plus the actual "meat" within the lambda expression.
这篇关于使用 Xptr 和 Function 调用 Rcpp 函数 - 仅适用于 xptr 案例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!