Rcpp:在 R 中调用 c++ 函数而不导出 c++ 函数

Rcpp: calling c++ function in R without exporting c++ function

本文关键字:c++ 函数 调用 Rcpp      更新时间:2023-10-16

我正在尝试用Rcpp制作一个包。我将所有C++函数都放在一个.cpp文件中,如下所示:

double meanvec(NumericVector x) {
int n = x.size();
double tot = 0;
for (int i = 0; i < n; i++) {
tot += x[i];
}
tot /= n;
return tot;
}
double inprod(NumericVector u, NumericVector v) {
int m = u.size();
double val = 0;
for (int i = 0; i < m; i++) {
val += u[i] * v[i];
}
return val;
}
NumericVector lincoef(NumericVector x, NumericVector y) {
int n = x.size();
double xm = meanvec(x);
double ym = meanvec(y);
NumericVector xa(n);
for (int i = 0; i < n; i++) {
xa[i] = x[i] - xm;
}
NumericVector ya(n);
for (int i = 0; i < n; i++) {
ya[i] = y[i] - ym;
}
double b1 = inprod(xa, ya) / inprod(xa, xa);
double b0 = ym - (b1 * xm);
NumericVector beta = NumericVector::create(b0, b1);
return beta;
}

基本上,最后一个函数将两个向量作为输入并输出单个向量。我想将此函数调用到一个单独的.R文件中,我正在尝试在其中编写另一个函数。像这样:

#' Title
#'
#' @param x Numeric vector.
#' @param y Numeric vector.
#'
#' @return
#' @export
linfit338 = function(x, y){
beta = .Call(`_pkg338_lincoef`, x, y)
fmod = function(x){
beta[1] + beta[2]*x
}
flist = list(beta, fmod)
return(flist)
}

这里的输出是一个列表,其中第一个元素是来自正在调用的C++函数的向量,第二个元素是创建的函数。当我尝试安装并重新启动时,我收到以下错误消息:

RcppExports.o:RcppExports.cpp:(.rdata+0x790): undefined reference to `_pkg338_lincoef'

我的猜测是这与导出函数有关。当我在C++文件中的lincoef函数上方添加// [[Rcpp::export]]时,我没有收到任何错误消息,并且我的最终R函数可以正常工作。但是,我的整个目标是我根本不希望导出lincoef函数。

有什么方法可以解决这个问题吗?我也愿意接受有关如何改进这些文件的组织的建议,因为这是我第一次使用Rcpp构建软件包。

我认为您可能混淆了导出C++代码以在 R 中使用的概念(通过// [[Rcpp::export]](,这与从包中导出 R 函数完全不同,即将这些功能提供给包的最终用户。

要使 Rcpp 函数完全可以从 R 中调用,您需要// [[Rcpp::export]]它们。如果不执行此操作,则 R 包中将不提供任何C++代码。

听起来您想做的是在软件包中使用 Rcpp 导出的函数,但对最终用户隐藏它们。这是 Rcpp 的一个常见用例,因为它允许您拥有一个充当C++代码的最终用户接口的 R 函数,同时让您在未来的开发中自由更改C++实现,而不会有破坏现有用户代码的风险。

在包中创建的任何函数(无论是 R 函数还是 Rcpp 导出的函数(都必须主动从包中导出,以便最终用户可以使用。这与// [[Rcpp::export]]不同,后者需要从包的 R 代码中访问C++函数。

只有在项目根目录的NAMESPACE文件中指定任何 R 函数时,才会从 R 包中导出这些函数。因此,要导出myfunction()您需要在命名空间文件中有一行表示export(myfunction)。您正在使用 roxygen2,只要您在 roxygen 框架中写入@export,它就会自动生成此行。使用 roxygen 导出系统的另一种方法是在NAMESPACE文件中指定一个exportPattern,该使用正则表达式仅导出名称与特定模式匹配的函数。

我通常的工作流程是通过编写我的C++函数来为任何 Rcpp 导出的函数添加句点,如下所示:

// [[Rcpp::export(.MyCppFunction)]]
int BoringFunction() { return 0; }

我现在可以从 R 调用 C++ 函数,如下所示:

MyRFunction <- function()
{
result <- .MyCppFunction()
return(result)
}

我的NAMESPACE文件的第一行如下所示:

exportPattern("^[[:alpha:]]+")

这意味着我的包中任何以字母开头的 R 函数都将被导出。由于我Rcpp::export的所有函数都以句点开头,因此我可以在 R 包内部使用它们,但它们不会导出给最终用户。

换句话说,包的最终用户可以调用MyRFunction()但如果他们尝试调用.MyCppFunction