Is it possible to use Rcpp to expose a C++ class to R when the class has a member taking an instance of that class?
Example:
#include <Rcpp.h>
class Test {
public:
Test(int x): x_(x) {}
int getValue() { return x_; }
void addValue(int y) { x_ += y; }
void merge(const Test& rhs) { x_ += rhs.x_; }
private:
int x_;
};
using namespace Rcpp;
RCPP_MODULE(mod_test) {
class_<Test>("Test")
.constructor<int>("sets initial value")
.method("getValue", &Test::getValue, "Returns the value")
.method("addValue", &Test::addValue, "Adds a value")
.method("merge", &Test::merge, "Merges another Test into this object")
;
}
Unfortunately that results in the following error:
error: no matching constructor for initialization of 'Test'
After reading and searching for answers, I came up with the idiom of separately including RcppCommon.h and then inserting a block like the following:
namespace Rcpp {
template <> Test as( SEXP x ) ;
}
Unfortunately that results in the following errors:
Error in dyn.load("/.../sourceCpp_86871.so") : unable to load shared object '/.../sourceCpp_86871.so':
dlopen(/.../sourceCpp_86871.so, 6): Symbol not found: __ZN4Rcpp2asI4TestEET_P7SEXPREC Referenced from: /.../sourceCpp_86871.so Expected in: flat namespace in /.../sourceCpp_86871.so
Is it possible to do this?
Is there an implementation for the 'as' specialization that I need to create? Is there an example somewhere of how to write it?
Alternatively is there an example of how to check and convert a SEXP back into the C++ object it "wraps"?
The proper as
conversion seems to be generated by inserting RCPP_EXPOSED_CLASS
.
The complete working example becomes:
#include <Rcpp.h>
class Test {
public:
Test(int x): x_(x) {}
int getValue() { return x_; }
void addValue(int y) { x_ += y; }
void merge(const Test& rhs) { x_ += rhs.x_; }
private:
int x_;
};
using namespace Rcpp;
RCPP_EXPOSED_CLASS(Test)
RCPP_MODULE(mod_test) {
class_<Test>("Test")
.constructor<int>("sets initial value")
.method("getValue", &Test::getValue, "Returns the value")
.method("addValue", &Test::addValue, "Adds a value")
.method("merge", &Test::merge, "Merges another Test into this object")
;
}
It works correctly now:
> Rcpp::sourceCpp('test.cpp')
> a = Test$new(2)
> b = Test$new(3)
> a$getValue()
[1] 2
> a$merge(b)
> a$getValue()
[1] 5
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