问题
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?
回答1:
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
回答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()
.
回答3:
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.
来源:https://stackoverflow.com/questions/12405655/returning-a-custom-object-from-a-wrapped-method-in-rcpp