У меня следующая проблема с модулем Rcpp:
давайте предположим, что у меня есть два класса в модуле Rcpp
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)
;
}
.
В данный момент компиляция не удалась, так как она не знает, что делать с типом возврата A.
Я подумал, что мог бы что-то сделать с Rcpp :: Xptr, однако затем я не могу связать это со структурой S4, сгенерированной Rcpp для класса A. Я фактически получаю объект внешнего указателя из метода в R.
Есть ли возможность получить правильно обернутый объект обратно из метода второго класса?
Спасибо,
Томас
Согласно ответу Дирка, я создал оболочку, которая может создать обернутый объект S4:
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 );
}
Тем не менее, я не знаю, как вернуть объект в качестве параметра метода / функции. Следующее не работает:
template <> A* as( SEXP obj){
Rcpp::List l(obj);
Rcpp::XPtr<A> xp( (SEXP) l[".pointer"] );
return (A*) xp;
}
Итак, как я могу получить внешний указатель на объект C ++ из объекта S4, предоставленного как SEXP в списке параметров?
Эта функция была добавлена в Rcpp 0.10.0
Были и другие причины, по которым ваш код не компилировался. Код ниже работает для меня:
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)
;
}
Цена, которую нужно заплатить, это вызвать макрос RCPP_EXPOSED_CLASS
для всех классов, которые:
С этим я получаю:
> b <- new( B )
> b$get_an_A( )
C++ object <0x10330a9d0> of class 'A' <0x1006f46e0>
> b$get_an_A( )$x
[1] 3
Это возможно если вы напишите обертку для этого. Они не падают, как манна с неба, вам нужно помочь компилятору, предоставив его, и он будет выбран.
Простой пример из 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 ));
}
Здесь класс из Boost преобразуется в класс Rcpp (Date), который затем возвращается (и даже там нам нужна явная перенос). Для более сложных классов вам нужны более сложные конвертеры.
Редактировать: И, конечно же, вы должны помнить, что все, что можно вызвать из R, все еще должно соответствовать основному SEXP foo(SEXP a, SEXP b, ...)
интерфейс, предписанный .Call()
,
Хорошо, я думаю, что понял. Но никаких гарантий.
Согласно ответу Дирка, я создал оболочку, которая может создать обернутый объект S4:
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 );
}
Если метод ожидает объект в качестве параметра (здесь указатель на этот объект), может быть полезна следующая обертка «как»:
template <> A* as( SEXP obj){
Rcpp::Environment e(obj);
Rcpp::XPtr<A> xp( (SEXP) e.get(".pointer") );
return (A*) xp;
}
Вы, конечно, также можете вернуть * xp, который позволяет принимать не указатели в качестве параметров, но это снова копирует объект.