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

Aid*_*nny 1 c++ r rcpp

我正在尝试使用 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;
}
Run Code Online (Sandbox Code Playgroud)

基本上,最后一个函数将两个向量作为输入并输出一个向量。我想将此函数调用到一个单独的.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)
}
Run Code Online (Sandbox Code Playgroud)

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

RcppExports.o:RcppExports.cpp:(.rdata+0x790): undefined reference to `_pkg338_lincoef'
Run Code Online (Sandbox Code Playgroud)

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

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

All*_*ron 10

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

为了让您的功能RCPP R里面调用可言,你需要// [[Rcpp::export]]他们。如果不这样做,则 R 包中将无法使用任何 C++ 代码。

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

您在包中创建的任何函数,无论是 R 函数还是 Rcpp 导出的函数,都必须主动从包中导出以供最终用户使用。这是一个与 不同的概念// [[Rcpp::export]],它是从包的​​ R 代码中访问 C++ 函数所必需的。

如果您NAMESPACE在项目根目录的文件中指定任何 R 函数,则只会从您的 R 包中导出它们。因此,要导出,myfunction()您需要export(myfunction)在 NAMESPACE 文件中包含一行。您使用的是 roxygen2,只要您@export在 roxygen 骨架中写入,它就会自动生成此行。使用 roxygen 的导出系统的替代方法是exportPatternNAMESPACE文件中指定一个使用正则表达式仅导出名称与特定模式匹配的函数。

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

// [[Rcpp::export(.MyCppFunction)]]
int BoringFunction() { return 0; }
Run Code Online (Sandbox Code Playgroud)

我现在可以像这样从 R 调用 C++ 函数:

MyRFunction <- function()
{
  result <- .MyCppFunction()
  return(result)
}
Run Code Online (Sandbox Code Playgroud)

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

exportPattern("^[[:alpha:]]+")
Run Code Online (Sandbox Code Playgroud)

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

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