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

时间:2013-10-30 15:24:08

标签: c r rcpp

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

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

...
# and in C code:
SEXP cpp_fn (SEXP arglist) {
}

但是.External正在评估...中的参数,所以如果我尝试类似

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

R_fn(x*y)

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

相比之下,以下内容适用于R:

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

f(x*y*z)
# x * y * z

我还有其他选择吗?显然,它可以做,因为R本身就可以用于许多功能,例如: substitute本身,但我不明白该怎么做。我添加了rcpp代码,因为我最终会在Rcpp使用此代码。

1 个答案:

答案 0 :(得分: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;
}