将未评估的表达式传递给C/C++

edd*_*ddi 14 c r rcpp

我想将一个函数的可变数量的参数传递给C/C++,但是希望保留参数不被评估,同时不希望在R中进行任何计算(除了调用C/C++之外)功能),即我不想调用substitute我的R函数.我认为我可以使用的一个选项就是.External像这样做smth:

R_fn = function(...) .External("cpp_fn", ...)

...
# and in C code:
SEXP cpp_fn (SEXP arglist) {
}
Run Code Online (Sandbox Code Playgroud)

然而,.External正在评估参数...,所以如果我尝试类似的东西

rm(x, y) # just making sure these don't exist

R_fn(x*y)
Run Code Online (Sandbox Code Playgroud)

我收到错误,因为R x*y 将其发送到函数之前尝试进行评估.

相比之下,R中的以下作品:

f = function(...) g(...)
g = function(x, ...) print(substitute(x))

f(x*y*z)
# x * y * z
Run Code Online (Sandbox Code Playgroud)

我还有其他选择吗?显然,它可以做,因为R本身为许多功能做了它,例如substitute它本身,但我不明白该怎么做.我添加了rcpp标签,因为我最终会使用这个标签Rcpp.

edd*_*ddi 5

一种可能性是做什么match.call(感谢Ricardo Saporta将我指向那个方向).这需要从R源代码中复制粘贴一些我不会在这里做的定义,但基本的想法是从中获取调用函数R_GlobalContext,然后从那里提取函数参数.粗略草图如下:

R_fn = function(...) .Call("cpp_fn")

// and in C++ code
Language cpp_fn() {
  SEXP sysp = ((RCNTXT*)R_GlobalContext)->sysparent;
  RCNTXT *cptr = (RCNTXT*)R_GlobalContext;

  while (cptr != NULL) {
    if (cptr->callflag & CTXT_FUNCTION && cptr->cloenv == sysp)
      break;
    cptr = cptr->nextcontext;
  }
  cptr = cptr->nextcontext; // because this is called from .Call and not from R_fn

  // and now cptr->promargs has the unevaluated arguments to do as one pleases
  // e.g.
  Language firstArg(R_PromiseExpr(CAR(cptr->promargs)));

  return firstArg;
}
Run Code Online (Sandbox Code Playgroud)

  • 使用非导出的 c api 是自找麻烦。 (2认同)