hi. i have been trying to understand how to pass objects back and forth by reference (in order to avoid copying). this works smoothly if one is calling a method on the object. but, i was having trouble figuring this out for "free functions" (i.e., non-member functions, i.e., non-methods). the term "free function" itself i discovered in Rcpp_modules.pdf.
the answer is to define a function which has the desired pass-by-reference class as its first parameter, as a pointer, and then list that function as a *.method* in the class_ field of the RCPP_MODULE() call. i.e. (see that attached for the gory details), given a class ---- class space2d ... ---- one defines a function or two: ---- space2d* psps(space2d* arg, int val) { arg->set(1, val); return arg; } void vps(space2d* arg, int val) { arg->set(1, val); } ---- and then does some module stuff: ---- RCPP_EXPOSED_CLASS(space2d) using namespace Rcpp; RCPP_MODULE(test6_module) { class_<space2d>("space2d") .constructor() .method("psps", &psps) .method("vps", &vps); } ---- in the above, changes made to arg in both psps() and vps() will be seen by the caller. in addition, the receiver of the return value of psps() will *also* hold a shared copy of the reference object. hth. (it might be a Nice Addition to remove the limitations of only one pass-by-reference, location in the formal parameters, etc. someday...) cheers, Greg ----
// problems passing arguments by reference // i had thought that one of the following methods had resulted in the // shared copy being modified. but, that was r.pixmap, when it was an // IntegerMatrix -- so was actually a bug in my code (which should // have called something like the C "NAMED()" macro, and then the C // function "duplicate" to copy it if the result was > 0). // but, the Rcpp_module.pdf document has this statement: "A free // function that takes a pointer to the target class as its first // parameter, followed by 0 or more (up to 65) parameters that can be // handled by Rcpp::as and returning a type that can be handled by // Rcpp::wrap or void." i am not sure what a "free function" is. // okay, define as a .method in the class, define the formal to be // space2d*, and it all works. see the "psps" and "vps" methods // below. // to run, first put the source in inc // (inc <- <SINGLEQUOTE><SOURCE><SINGLEQUOTE>) // then do something like: #if 0 require(inline); require(Rcpp); cld <- cxxfunction(,plugin="Rcpp", includes=inc); clm <- Module("test6_module", getDynLib(cld)); space2d <- clm$space2d; ## basic reference class aliasing (all normal) x <- new(space2d); y <- x; print(x$get(1)); print(y$get(1)); print("change"); x$set(1,1); print(x$get(1)); print(y$get(1)); print("ss"); x <- new(space2d); print(x$get(1)); y <- clm$ss(x,1); print(x$get(1)); print(y$get(1)); print("vs"); x <- new(space2d); print(x$get(1)); clm$vs(x, 1); print(x$get(1)); print("ll"); x <- new(space2d); print(x$get(1)); y <- clm$ll(list(x), 1) print(x$get(1)); print(y[[1]][[1]]$get(1)); print("vl"); x <- new(space2d); print(x$get(1)); clm$vl(list(x), 1) print(x$get(1)); print("imim"); x <- matrix(0,nrow=2,ncol=2) print(x[2,2]); y <- clm$imim(x,1) print(x[2,2]); print(y[2,2]); print("vim"); x <- matrix(0,nrow=2,ncol=2) print(x[2,2]); clm$vim(x,1) print(x[2,2]); print("psps"); x <- new(space2d); print(x$get(1)); y <- x$psps(1) print(x$get(1)); print(y$get(1)); print("are x and y linked?") y$set(1,2) print(x$get(1)); print(y$get(1)); print("vps"); x <- new(space2d); print(x$get(1)); x$vps(1) print(x$get(1)); if (FALSE && "the following tests do not compile, so are commented out") { print("imrim"); x <- matrix(0,nrow=2,ncol=2); print(x[2,2]); y <- clm$imrim(x,1); print(x[2,2]); print(y[2,2]); print("vrim"); x <- matrix(0,nrow=2,ncol=2); print(x[2,2]); clm$vrim(x,1); print(x[2,2]); } #endif /* 0 */ #include <R.h> #include <RcppCommon.h> #include <Rcpp/S4.h> #include <Rcpp.h> class space2d { public: std::vector<int> values; // the actual bits public: space2d() { values = std::vector<int>(16,0); } inline int get(int p) const { return values[p]; /* XXX there was a "1+" here */ } inline void set(int p, int val) { values[p] = val; }; }; ///////////////////////////// Rcpp::List space2d2rlist(space2d space) { return Rcpp::List::create(Rcpp::Named("space2d", Rcpp::module_wrap<space2d>(space))); } space2d rlist2space2d(Rcpp::List list) { return list[0]; } ///////////////////////////// space2d ss(space2d arg, int val) { arg.set(1, val); return arg; } void vs(space2d arg, int val) { arg.set(1, val); } Rcpp::List ll(Rcpp::List arg, int val) { space2d s2d = rlist2space2d(arg); s2d.set(1, val); return Rcpp::List::create(Rcpp::Named("space2d", space2d2rlist(s2d))); } void vl(Rcpp::List arg, int val) { space2d s2d = rlist2space2d(arg); s2d.set(1, val); } Rcpp::IntegerMatrix imim(Rcpp::IntegerMatrix arg, int val) { arg(1,1) = val; return arg; } void vim(Rcpp::IntegerMatrix arg, int val) { arg(1,1) = val; } #if defined(FAIL) Rcpp::IntegerMatrix imrim(Rcpp::IntegerMatrix& arg, int val) { arg(1,1) = val; return arg; } void vrim(Rcpp::IntegerMatrix& arg, int val) { arg(1,1) = val; } #endif /* defined(FAIL) */ space2d* psps(space2d* arg, int val) { arg->set(1, val); return arg; } void vps(space2d* arg, int val) { arg->set(1, val); } RCPP_EXPOSED_CLASS(space2d) using namespace Rcpp; RCPP_MODULE(test6_module) { class_<space2d>("space2d") .constructor() .method("get", &space2d::get) .method("set", &space2d::set) .method("psps", &psps) .method("vps", &vps); function("ss", &ss); function("vs", &vs); function("ll", &ll); function("vl", &vl); function("imim", &imim); function("vim", &vim); #if defined(FAIL) function("imrim", &imrim); function("vrim", &vrim); #endif /* defined(FAIL) */ }
_______________________________________________ Rcpp-devel mailing list Rcpp-devel@lists.r-forge.r-project.org https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel