2016-04-21 88 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