2016-04-21 32 views
0

使用Rcpp将某些常量从C++代码导出到R中的最正确方法是什么?如何使用Rcpp将常量从C++导出为R

我正在为一些C库编写包装器,并且在库调用中可能会使用API​​头中定义的一些常量。因为我想在R代码中尽可能接近地模拟API,所以我想将这些常量从C中导出到R.

+0

从狭义上讲,您可以通过'.onLoad()'或'.onAttach()'在R代码中定义它们。无论是在R代码中,还是通过循环来自C++的元素通过辅助函数循环。做一些自动化更难。我有时候希望将它用于'enum'类型,但也没有好的解决方案。 –

回答

2

在RCPP代码,您可以访问所有存在于正在运行的R会话中的R环境作为Rcpp Environment对象。然后您可以通过该对象读取/写入条目。

所以你可以做的就是编写一个Rcpp函数,它将条目分配给底层头文件中定义的常量。当然,你必须在函数的编译中包含头文件以使其工作。

例子:

library(Rcpp); 
cppFunction(
    includes='#define A 3', ## replace this with includes='#include "someheader.h"' 
    'void assignConstants() { Environment ge = Environment::global_env(); ge["A"] = A; }' 
); 
A; 
## Error: object 'A' not found 
assignConstants(); 
A; 
## [1] 3 

当你的包装的用户加载包装,装载过程可以通过cppFunction()电话(定义两个assignConstants()功能和所有的实际包装函数是一举两得定义RCPP功能有用的东西),然后运行assignConstants()函数来实际定义全局环境中的常量。

+1

我不知道为什么这是downvoted。看起来像许多可能和合理的方法之一。 –

2

可能有几种方法可以做到这一点,但一种简单的方法是导出一个函数,返回一个常量值并为其创建一个活动绑定。该机制将很好的工作无论您是使用R函数或C/C++函数,它出现的基本功能已被删除后还要工作:

#include <Rcpp.h> 

// [[Rcpp::export]] 
double MyConstant() { 
    return 1.54; 
} 

/***R 

MyConstant2 <- function() 1.54 

makeActiveBinding("my_constant", MyConstant, .GlobalEnv) 
makeActiveBinding("my_constant2", MyConstant2, .GlobalEnv) 

my_constant 
#[1] 1.54 

my_constant2 
#[1] 1.54 

inherits(try(my_constant <- 2.5, TRUE), "try-error") 
#[1] TRUE 

inherits(try(my_constant2 <- 2.5, TRUE), "try-error") 
#[1] TRUE 

rm(MyConstant, MyConstant2) 

my_constant 
#[1] 1.54 

my_constant2 
#[1] 1.54 

inherits(try(my_constant <- 2.5, TRUE), "try-error") 
#[1] TRUE 

inherits(try(my_constant2 <- 2.5, TRUE), "try-error") 
#[1] TRUE 

*/ 
+0

由于这些是常量,因此不需要活动绑定来检索常量的值。所需要的只是环境条目的固定值。但这是一个有趣的想法。 – bgoldst

+0

这是真的,但我主要有绑定来保留'my_constant'的'const'-ness(例如'my_constant < - ...'是一个错误),而'assignConstants(); A < - 5'是允许的。尽管如果OP正在制作一个包并导出这些常量,那么在任何情况下都应该保护它们免于分配。 – nrussell