Reputation: 42367
I've got two Rcpp-wrapped classes, A
and B
. A
's constructor extracts some information from its parameter, and prints it out to prove it worked.
B
takes an object of A
as a constructor parameter — and reports an error as if extraction in A
's constructor failed. But as A
did print out the extracted data, it couldn't fail.
How do I get B
to accept A
as a parameter without erroring out?
Minimal reproducible example:
library(Rcpp)
Rcpp::sourceCpp(code='
#include <Rcpp.h>
struct A {
Rcpp::NumericVector y;
A(Rcpp::List x)
: y(Rcpp::as<Rcpp::NumericVector>(x["foo"]))
{
Rcpp::Rcout << y;
}
};
struct B {
B(A x) { }
};
RCPP_MODULE(A) {
Rcpp::class_<A>("A")
.constructor<Rcpp::List>();
}
RCPP_MODULE(B) {
Rcpp::class_<B>("B")
.constructor<A>();
}
')
Aobj <- new(A, list(foo=1:3))
Bobj <- new(B, Aobj)
Output:
> source('testcase.R', echo=TRUE)
> library(Rcpp)
> Rcpp::sourceCpp(code='
+ #include <Rcpp.h>
+
+ struct A {
+ Rcpp::NumericVector y;
+
+ A(Rcpp::List x)
+ : y(Rcpp::as<Rcpp::NumericVector> .... [TRUNCATED]
> Aobj <- new(A, list(foo=1:3))
1 2 3
> Bobj <- new(B, Aobj)
Error in new_CppObject_xp(fields$.module, fields$.pointer, ...) :
Index out of bounds: [index='foo'].
>
Upvotes: 3
Views: 275
Reputation: 26833
I'll try to explain why your solution works. With RCPP_MODULE(A)
you are exposing the C++ struct A
as a reference class in R. That is done automatically. However, when you call Bobj <- new(B, Aobj)
, there is no information how to convert from this reference class to the required C++ struct. By using RCPP_EXPOSED_CLASS(A)
you are creating specialization of Rcpp::wrap
and Rcpp::as
to convert between C++ and R objects in both ways. Since we are only missing the R to C++ conversion, i.e. Rcpp::as
, the following is also enough:
#include <RcppCommon.h>
struct A;
RCPP_EXPOSED_AS(A)
#include <Rcpp.h>
struct A {
Rcpp::NumericVector y;
A(Rcpp::List x)
: y(Rcpp::as<Rcpp::NumericVector>(x["foo"]))
{
Rcpp::Rcout << y;
}
};
struct B {
B(A x) { }
};
RCPP_MODULE(A) {
Rcpp::class_<A>("A")
.constructor<Rcpp::List>();
}
RCPP_MODULE(B) {
Rcpp::class_<B>("B")
.constructor<A>();
}
/*** R
Aobj <- new(A, list(foo=1:3))
Bobj <- new(B, Aobj)
*/
Upvotes: 4
Reputation: 42367
When things are not working, it's good to (re-)read some documentation. Specifically, Rcpp Extending (PDF), section 3.2.
I added the following at the beginning of the C++ code:
#include <RcppCommon.h>
struct A;
RCPP_EXPOSED_CLASS(A);
…and it works fine now. I admit I don't fully understand what happens here yet, but this solution is solving both the MWE and my original code problems.
Upvotes: 3