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
[email protected]
https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel