scaramouche
scaramouche

Reputation: 471

Using Rcpp to expose a constructor that takes a pointer to an object as a parameter

I have the following very simple code that defines a class B that takes as a parameter a pointer to an object of class A.

The code works perfectly if I compile it as standalone C++, but I haven't been able to expose class B using Rcpp. I must be doing something wrong in the line .constructor<A>() near the end. Have tried all the combinations of &, *, etc. and nothing works. I'm lost after many hours of trying. Any ideas are welcome.

#include <Rcpp.h>

using namespace Rcpp;

class A {
public:
  A(int val_) { val = val_; }
  int val;
};

class B {
public:
  B(A& ptr_) { ptr = &ptr_; }
  int getval() { return (this->ptr->val); }
  A *ptr;
};

RCPP_MODULE(module_cpp) {
    using namespace Rcpp;

    class_<A>("A")
    .constructor<int>()
    .field("val", &A::val)
    ;

    class_<B>("B")
    .constructor<A>()
    ;
}

Upvotes: 3

Views: 225

Answers (1)

Ralf Stubner
Ralf Stubner

Reputation: 26823

Let's try to be stubborn: Your constructor for B expects a reference to an A, so we should expose it as such, i.e. .constructor<A&>(). Doing so I get the error

invalid user-defined conversion from ‘SEXP’ {aka ‘SEXPREC*’} to ‘A&’

Basically we want to create something that's callable within R (the constructor for B), but we can only use SEXP as type for the arguments. And currently it is unknown how to convert between SEXP and A&. This sort of conversion would be the task of Rcpp::as (and Rcpp::wrap for the reverse), which are covered in the Rcpp-extending vignette. For Rcpp Modules, we can take the shortcut provided by RCPP_EXPOSED_AS and friends, c.f. section 2.2.11 in the Rcpp-modules vignette.

Here a complete example with added verification code:

#include <Rcpp.h>

using namespace Rcpp;

class A {
public:
    A(int val_) { val = val_; }
    int val;
};

class B {
public:
    B(A& ptr_) { ptr = &ptr_; }
    int getval() { return (this->ptr->val); }
    A *ptr;
};

RCPP_EXPOSED_AS(A);

RCPP_MODULE(module_cpp) {
    using namespace Rcpp;

    class_<A>("A")
        .constructor<int>()
        .field("val", &A::val)
    ;

    class_<B>("B")
        .constructor<A&>()
        .method("getVal", &B::getval)
    ;
}

/***R
a <- new(A, 42)
b <- new(B, a)
b$getVal()
*/ 

Output:

> Rcpp::sourceCpp('61898230.cpp')

> a <- new(A, 42)

> b <- new(B, a)

> b$getVal()
[1] 42

Upvotes: 6

Related Questions