My goal is to build a dataset class and a model class, and expose both of them to R. The model class has a train() method that takes a reference to a dataset instance, and this seems to be at the root of my issue. Here's what this looks like
//glue.cpp
#include <Rcpp.h>
class MyData
{
public:
MyData() = default;
};
class MyModel
{
public:
MyModel() = default;
void train(const MyData& data) { Rcpp::Rcout << "training model... "; };
};
// Expose MyData
RCPP_MODULE(MyData){
Rcpp::class_<MyData>("MyData")
.constructor()
;
}
// Expose MyModel
RCPP_MODULE(MyModel){
Rcpp::class_<MyModel>("MyModel")
.constructor()
.method("train", &MyModel::train)
;
}
(I should note that this file, glue.cpp, is embedded in an R package.) When I remove this line, .method("train", &MyModel::train), I can compile this without error via pkgbuild::compile_dll(). With it, I get the nasty error below
─ installing *source* package ‘SimpleCppModel’ ...
** libs
clang++ -I"/Library/Frameworks/R.framework/Resources/include" -DNDEBUG -I"/Library/Frameworks/R.framework/Versions/3.5/Resources/library/Rcpp/include" -I/usr/local/include -std=c++14 -fPIC -Wall -g -O2 -c RcppExports.cpp -o RcppExports.o
clang++ -I"/Library/Frameworks/R.framework/Resources/include" -DNDEBUG -I"/Library/Frameworks/R.framework/Versions/3.5/Resources/library/Rcpp/include" -I/usr/local/include -std=c++14 -fPIC -Wall -g -O2 -c glue.cpp -o glue.o
In file included from glue.cpp:3:
In file included from /Library/Frameworks/R.framework/Versions/3.5/Resources/library/Rcpp/include/Rcpp.h:27:
In file included from /Library/Frameworks/R.framework/Versions/3.5/Resources/library/Rcpp/include/RcppCommon.h:168:
In file included from /Library/Frameworks/R.framework/Versions/3.5/Resources/library/Rcpp/include/Rcpp/as.h:25:
/Library/Frameworks/R.framework/Versions/3.5/Resources/library/Rcpp/include/Rcpp/internal/Exporter.h:31:28: error: no matching constructor for initialization of 'MyData'
Exporter( SEXP x ) : t(x){}
^ ~
/Library/Frameworks/R.framework/Versions/3.5/Resources/library/Rcpp/include/Rcpp/as.h:87:41: note: in instantiation of member function 'Rcpp::traits::Exporter<MyData>::Exporter' requested here
::Rcpp::traits::Exporter<T> exporter(x);
^
/Library/Frameworks/R.framework/Versions/3.5/Resources/library/Rcpp/include/Rcpp/as.h:152:26: note: in instantiation of function template specialization 'Rcpp::internal::as<MyData>' requested here
return internal::as<T>(x, typename traits::r_type_traits<T>::r_category());
^
/Library/Frameworks/R.framework/Versions/3.5/Resources/library/Rcpp/include/Rcpp/InputParameter.h:72:54: note: in instantiation of function template specialization 'Rcpp::as<MyData>' requested here
ConstReferenceInputParameter(SEXP x_) : obj( as<T>(x_) ){}
^
/Library/Frameworks/R.framework/Versions/3.5/Resources/library/Rcpp/include/Rcpp/module/Module_generated_CppMethod.h:129:58: note: in instantiation of member function 'Rcpp::ConstReferenceInputParameter<MyData>::ConstReferenceInputParameter' requested here
typename Rcpp::traits::input_parameter<U0>::type x0(args[0]);
^
/Library/Frameworks/R.framework/Versions/3.5/Resources/library/Rcpp/include/Rcpp/module/Module_generated_CppMethod.h:127:5: note: in instantiation of member function 'Rcpp::CppMethod1<MyModel, void, const MyData &>::operator()' requested here
CppMethod1( Method m) : method_class(), met(m) {}
^
/Library/Frameworks/R.framework/Versions/3.5/Resources/library/Rcpp/include/Rcpp/module/Module_generated_method.h:59:27: note: in instantiation of member function 'Rcpp::CppMethod1<MyModel, void, const MyData &>::CppMethod1' requested here
AddMethod( name_, new CppMethod1<Class,RESULT_TYPE,U0>(fun), valid, docstring);
^
glue.cpp:30:4: note: in instantiation of function template specialization 'Rcpp::class_<MyModel>::method<void, const MyData &>' requested here
.method("train", &MyModel::train)
^
glue.cpp:5:7: note: candidate constructor (the implicit copy constructor) not viable: cannot convert argument of incomplete type 'SEXP' (aka 'SEXPREC *') to 'const MyData' for 1st argument
class MyData
^
glue.cpp:5:7: note: candidate constructor (the implicit move constructor) not viable: cannot convert argument of incomplete type 'SEXP' (aka 'SEXPREC *') to 'MyData' for 1st argument
glue.cpp:8:3: note: candidate constructor not viable: requires 0 arguments, but 1 was provided
MyData() = default;
^
1 error generated.
make: *** [glue.o] Error 1
ERROR: compilation failed for package ‘SimpleCppModel’
─ removing ‘/private/var/folders/dn/9lp6j6j14t1137ftnnk27wyw0000gn/T/RtmpBqDLoF/devtools_install_4d775ed17ea2/SimpleCppModel’
Error in processx::run(bin, args = real_cmdargs, stdout_line_callback = real_callback(stdout), :
System command error
What gives?
As mentioned by Dirk in the comments, you will need as<>and wrap specializations for MyData. In your case, you can use the easiest solution from the "Extending Rcpp" vignette: RCPP_EXPOSED_CLASS. You just have to be careful when you include which header from Rcpp:
#include <Rcpp.h>
class MyData
{
public:
MyData() = default;
};
RCPP_EXPOSED_CLASS(MyData)
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()
;
}
// Expose MyModel
RCPP_MODULE(MyModel){
Rcpp::class_<MyModel>("MyModel")
.constructor()
.method("train", &MyModel::train)
;
}
/***R
myData <- new(MyData)
myModel <- new(MyModel)
myModel$train(myData)
*/
As you found out in your answer, this even works after including Rcpp.h.
It still makes sense to go through the mentioned gallery article as well the vignette, though.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With