14

I have the following problem with the Rcpp module: let's assume I've two classes in a Rcpp module

class A {
  public:
    int x;
};

class B
  public:
    A get_an_a(){
      A an_a();
      an_a.x=3;
      return an_a;
    }
};

RCPP_MODULE(mod){
  using namespace Rcpp ;
  class_<A>("A")
   .constructor()
   .property("x",&A::get_x)
  ;
  class_<B>("B)
   .constructor()
   .method("get_an_A",&get_an_a)
  ;
}

.

Right now compilation fails as it does not know what to do with the return type of A.

I figured I could do something with Rcpp::Xptr, however, then I can't connect it to the S4 structure that Rcpp generated for the class A. I actually get an external pointer object from the method in R.

Is there any possiblity to get a correctly wrapped object back from a method of the second class?

Thanks, Thomas

[edit]

According to Dirk's answer I constructed a wrapper that can create the wrapped S4 object:

template <> SEXP wrap(const A &obj) { // insprired from "make_new_object" from Rcpp/Module.h
  Rcpp::XPtr<A> xp( new A(obj), true ) ; // copy and mark as finalizable
  Function maker=Environment::Rcpp_namespace()[ "cpp_object_maker"];
  return maker ( typeid(A).name() , xp );
}

Still, I don't know how to get the object back in as an parameter to a method/function. The following is not working:

template <> A* as( SEXP obj){
  Rcpp::List l(obj);
  Rcpp::XPtr<A> xp( (SEXP) l[".pointer"] );
  return (A*) xp;
}

So how could I get the external pointer to the C++ object from the S4 object provided as SEXP in the parameter list?

Romain Francois
  • 17,432
  • 3
  • 51
  • 77
Thomas Handorf
  • 371
  • 5
  • 11

3 Answers3

13

This feature has been added in Rcpp 0.10.0

There were other reasons why your code did not compile. The code below works for me:

class A {
  public:
    A(int x_) : x(x_){}

    int x;
};

class B {
  public:
    A get_an_a(){
      A an_a(3);
      return an_a;
    }
};
RCPP_EXPOSED_CLASS(A)
RCPP_EXPOSED_CLASS(B)

RCPP_MODULE(stackmod){
  using namespace Rcpp ;
  class_<A>("A")
   .constructor<int>()
   .field("x",&A::x)
  ;
  class_<B>("B")
   .constructor()
   .method("get_an_A",&B::get_an_a)
  ;
}

The price to pay is to call the macro RCPP_EXPOSED_CLASS for all classes that:

  • One of your module is exposing
  • You want to use as result of an exposed method or as a parameter

With this, I get:

> b <- new( B )
> b$get_an_A( )
C++ object <0x10330a9d0> of class 'A' <0x1006f46e0>
> b$get_an_A( )$x
[1] 3
Romain Francois
  • 17,432
  • 3
  • 51
  • 77
2

It is possible if you write a wrapper for it. Those don't fall like manna from the sky, you need to aid the compiler by providing it and it will then get picked.

Simple example from RcppBDT:

template <> SEXP wrap(const boost::gregorian::date &d) {
    // convert to y/m/d struct
    boost::gregorian::date::ymd_type ymd = d.year_month_day();     
    return Rcpp::wrap(Rcpp::Date( ymd.year, ymd.month, ymd.day ));
}

Here a class from Boost is converted to an Rcpp class (Date) which is then returned (and even there we need an explicit wrap). For more complex classes you need more complex converters.

Edit: And, of course, you need to keep in mind that anything callable from R still needs to conform to the basic SEXP foo(SEXP a, SEXP b, ...) interface prescribed by .Call().

Dirk Eddelbuettel
  • 360,940
  • 56
  • 644
  • 725
  • 1
    Dirk, thanks for the really quick response. Unfortunately your solution would only work if I could translate A into a R type and use the wrap() and as() functions to mediate the calls. However, what I would really like to have is the wrapper class that Rcpp creates for class A (`` - I think) . I tried to track down the constructor that does that when I call `a<-new(A)` from R but wasn't able to find that. So I think I just need to create the same data structure as the constructor does, which could then be done in a wrapper. Am I right? – Thomas Handorf Sep 13 '12 at 14:03
  • I have no idea. If you want real help, post something reproducible to the mailing list. It is near impossible to say anything meaningful give the three lines of code you supplied. – Dirk Eddelbuettel Sep 13 '12 at 14:08
  • 1
    Hi Dirk, I partly figured it out. I can return wrapped objects to R. I edited the question and posted the code there. Still, I don't know how to access the C++ object in the S4 object. I hope the code I posted above makes my question a bit clearer. – Thomas Handorf Sep 17 '12 at 09:25
  • See other reply. Rcpp > 0.9.15 does it. – Romain Francois Oct 25 '12 at 08:23
1

Ok, I think I got it. But no guaranties. According to Dirk's answer I constructed a wrapper that can create the wrapped S4 object:

template <> SEXP wrap(const A &obj) { // insprired from "make_new_object" from Rcpp/Module.h
  Rcpp::XPtr<A> xp( new A(obj), true ) ; // copy and mark as finalizable
  Function maker=Environment::Rcpp_namespace()[ "cpp_object_maker"];
  return maker ( typeid(A).name() , xp );
}

If a method is expecting an object as parameter (here a pointer to that object), the following "as" wrapper may be useful:

template <> A* as( SEXP obj){
  Rcpp::Environment e(obj);
  Rcpp::XPtr<A> xp( (SEXP) e.get(".pointer") );
  return (A*) xp;
}

you may of course also return *xp which allows taking non-pointers as parameters , but that again copies the object.

Thomas Handorf
  • 371
  • 5
  • 11