I'd like to pass a variable number of arguments from a function to C/C++, but would like to leave the arguments unevaluated and at the same time don't want to do any computations in R (aside from calling the C/C++ function), i.e. I don't want to call substitute in my R function. One option for this that I thought I could use is .External and doing smth like this:
R_fn = function(...) .External("cpp_fn", ...)
...
# and in C code:
SEXP cpp_fn (SEXP arglist) {
}
However .External is evaluating arguments in ..., so if I try something like
rm(x, y) # just making sure these don't exist
R_fn(x*y)
I get an error because R is trying to evaluate x*y before sending it to the function.
To contrast, the following works in R:
f = function(...) g(...)
g = function(x, ...) print(substitute(x))
f(x*y*z)
# x * y * z
What other options do I have? Clearly it's possible to do as R itself does it for a number of functions, e.g. substitute itself, but I don't understand how to do it. I added the rcpp tag because my eventual usage of this is going to be in Rcpp.
One possibility is to do what match.call does (thanks to Ricardo Saporta for pointing me in that direction). This requires copy-pasting a few definitions from R source code that I won't do here, but the basic idea is to get the calling function from R_GlobalContext and then extract the function arguments from there. The rough sketch is as follows:
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With