Передача неоцененных выражений в C/С++
Я бы хотел передать переменное количество аргументов из функции в C/С++, но хотел бы оставить аргументы необоснованными и в то же время не делать никаких вычислений в R (кроме вызова C/С++), т.е. я не хочу вызывать substitute
в моей функции R. Один из вариантов для этого, который, как я думал, я мог бы использовать, - это .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
Одна из возможностей - сделать то, что match.call
(спасибо Рикардо Сапорте за то, что указал мне в этом направлении). Для этого требуется скопировать несколько определений из исходного кода 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;
}