Search code examples
c++ooprcpp

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>()
    ;
}

Solution

  • 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