Konstantin Sorokin
Konstantin Sorokin

Reputation: 117

How to export constants from C++ into R with Rcpp

What is the most correct way to export some constants from C++ code into R using Rcpp?

I am writing a wrapper for some C library and there are some constants defined in library's headers which may be used in API calls. Since I want to mimic that API as close as possible in R code I'd like to export these constants from C to R.

Upvotes: 2

Views: 372

Answers (2)

bgoldst
bgoldst

Reputation: 35314

In Rcpp code you can get access to all the R environments that exist in the running R session as Rcpp Environment objects. You can then read/write entries through the object.

So what you can do is write an Rcpp function that assigns entries to the constants defined in the underlying header file. Of course, you'll have to include the header file in the compilation of the function in order for it to work.

Example:

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

When the user of your wrapper loads the wrapper, the loading process can both define the Rcpp functions via cppFunction() calls (to define both the assignConstants() function and all the actual wrapper functions that do useful things) and then run the assignConstants() function to actually define the constants in the global environment.

Upvotes: 3

nrussell
nrussell

Reputation: 18602

There are probably a couple of ways to do this, but a simple approach would be to export a function that returns a constant value and create an active binding to it. The mechanism would work just as well whether you are using an R function or C/C++ function, and it appears to work even after the underlying function has been removed:

#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

*/

Upvotes: 3

Related Questions