Сначала я должен заявить, что пример в моем вопросе слишком прост. В действительности, класс MyData имеет метод, подобный void fill(const Rcpp::NumericMatrix& dat) { Rcpp::Rcout << "filling data... " << std::endl; };
, он зависит от Rcpp::NumericMatrix
, поэтому мне необходимо #include <Rcpp.h>
, прежде чем я объявлю MyData.
Вот два решения, которые я нашел, но я не использовал их достаточно, чтобы узнать, есть ли какие-то "ошибки".
Решение 1 - макрос RCPP_EXPOSED_CLASS ()
Здесь я использую макрос RCPP_EXPOSED_CLASS () как , описанный Романом Франсуа . (Спасибо, Ральф, за то, что указал мне на этот самородок.)
#include <Rcpp.h>
class MyData;
class MyModel;
RCPP_EXPOSED_CLASS(MyData)
RCPP_EXPOSED_CLASS(MyModel)
class MyData
{
public:
MyData() = default;
void fill(const Rcpp::NumericMatrix& dat) { Rcpp::Rcout << "filling data... " << std::endl; };
};
class MyModel
{
public:
MyModel() = default;
void train(const MyData& data) { Rcpp::Rcout << "training model... " << std::endl; };
};
// Expose MyData
RCPP_MODULE(MyData){
Rcpp::class_<MyData>("MyData")
.constructor()
.method("fill", &MyData::fill)
;
}
// Expose MyModel
RCPP_MODULE(MyModel){
Rcpp::class_<MyModel>("MyModel")
.constructor()
.method("train", &MyModel::train)
;
}
/***R
myData <- new(MyData)
myModel <- new(MyModel)
myModel$train(myData)
*/
Решение 2 - Используйте Rcpp :: XPtr
Это решение основано на шаблоне проектирования , обсужденном здесь . По сути, я просто создаю указатель на объект C ++ и использую функции-оболочки для его обработки. Вот пример того, как это может выглядеть.
#include <Rcpp.h>
class MyData
{
public:
MyData() = default;
void fill(const Rcpp::NumericMatrix& dat) { Rcpp::Rcout << "filling data... " << std::endl; };
};
class MyModel
{
public:
MyModel() = default;
void train(const MyData& data) { Rcpp::Rcout << "training model... " << std::endl; };
};
// [[Rcpp::export]]
SEXP make_dataset() {
MyData* datPtr = new MyData();
Rcpp::XPtr<MyData> datXPtr(datPtr);
return datXPtr;
}
// [[Rcpp::export]]
SEXP make_model() {
MyModel* mdlPtr = new MyModel();
Rcpp::XPtr<MyModel> mdlXPtr(mdlPtr);
return mdlXPtr;
}
// [[Rcpp::export]]
void train_model(SEXP mdlXPtr, SEXP datXPtr) {
Rcpp::XPtr<MyModel> mdlPtr(mdlXPtr);
Rcpp::XPtr<MyData> datPtr(datXPtr);
mdlPtr->train(*datPtr);
}
/***R
myData <- make_dataset()
myModel <- make_model()
train_model(myModel, myData)
*/
Недостатком этого метода является то, что, AFAIK, нет очевидного способа проверить тип объекта, на который указывает XPtr. Например, для меня не очевидно, как сделать недействительными плохие звонки, такие как train_model(myData, myModel)
.