1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
|
// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*-
//
// Simple example showing how expose a C++ function with custom data types
// This is a continuation of rinside_sample9.cpp
//
// Copyright (C) 2014 Christian Authmann
#include <iostream>
/*
* We have a simple data type with two values.
*/
class Foo {
public:
Foo(int a, int b) : a(a), b(b) {
}
~Foo() {
}
// The compiler will add the default copy constructor, so this class is copyable.
int a, b;
};
/*
* We define converters between Foo and R objects, see
* http://cran.r-project.org/web/packages/Rcpp/vignettes/Rcpp-extending.pdf
*/
#include <RcppCommon.h>
/*
* These template declarations must be after RcppCommon.h and before Rcpp.h
* The implementation can follow later, when all of Rcpp/Rinside is available.
*/
namespace Rcpp {
template<> SEXP wrap(const Foo &f);
template<> Foo as(SEXP sexp);
}
#include <Rcpp.h>
#include <RInside.h>
/*
* After including Rcpp/Rinside, we can implement the converters.
*/
template<> SEXP Rcpp::wrap(const Foo &f) {
Rcpp::List list;
list["a"] = f.a;
list["b"] = f.b;
// Like all internal Rcpp datatypes, the List can be autoconverted to a SEXP, so we can just return it.
// This is equivalent to: return Rcpp::wrap(list)
return list;
}
template<> Foo Rcpp::as(SEXP sexp) {
Rcpp::List list = Rcpp::as<Rcpp::List>(sexp);
// Note: This does not work when compiled using clang with Rcpp 0.11.2 and older
return Foo(
list["a"],
list["b"]
);
}
// a c++ function we wish to expose to R
Foo swapFoo(Foo &input) {
Foo result(input.b, input.a);
return result;
}
int main(int argc, char *argv[]) {
// create an embedded R instance
RInside R(argc, argv);
// expose the "swapFoo" function in the global environment
R["swapFoo"] = Rcpp::InternalFunction( &swapFoo );
// create a foo instance and expose it
Foo f(0, 42);
R["foo"] = f;
// call it, getting another Foo object
Foo result = R.parseEvalNT(
//"print(foo);" // a=0, b=42
"foo$a = 12;"
//"print(foo);" // a=12, b=42
"foo = swapFoo(foo);"
//"print(foo);" // a=42, b=12
"foo;" // return the object
);
std::cout << " Got result a=" << result.a << ", b=" << result.b << std::endl;
std::cout << " Expected a=42, b=12" << std::endl;
}
|