\pkg{Rcpp} facilitates data interchange between \proglang{R} and
\proglang{C++} through the templated functions Rcpp::as
(for
conversion of objects from \proglang{R} to \proglang{C++}) and
Rcpp::wrap
(for conversion from \proglang{C++} to \proglang{R}). In
other words, we convert between the so-called \proglang{S}-expression
pointers (in type SEXP
) to a templated \proglang{C++} type, and vice
versa. The corresponding function declarations are as follows:
```{Rcpp, eval = FALSE}
// conversion from R to C++
template
// conversion from C++ to R
template
These converters are often used implicitly, as in the following code chunk: ```{Rcpp} #include <Rcpp.h> using namespace Rcpp; // [[Rcpp::export]] List fx(List input) { // we get a list from R // pull std::vector<double> from R list // this is achieved through an implicit // call to Rcpp::as std::vector<double> x = input["x"]; // return an R list; this is achieved // through an implicit call to Rcpp::wrap return List::create(_["front"] = x.front(), _["back"] = x.back()); }
Example:
## Run sourceCpp compilation to include file # Rcpp::sourceCpp(file= "code.cpp") input <- list( x = seq(1, 10, by = 0.5) ) fx(input)
The \pkg{Rcpp} converter function Rcpp::as
and Rcpp::wrap
have been
designed to be extensible to user-defined types and third-party types.
Rcpp::wrap
The \pkg{Rcpp::wrap} converter is extensible in essentially two ways : intrusive and non-intrusive.
When extending \pkg{Rcpp} with your own data type, the recommended way is to
implement a conversion to SEXP
. This lets Rcpp::wrap
know
about the new data type. The template meta programming (or TMP) dispatch is able to
recognize that a type is convertible to a SEXP
and
Rcpp::wrap
will use that conversion.
The caveat is that the type must be declared before the main header
file Rcpp.h
is included.
```{Rcpp, eval = FALSE}
class Foo { public: Foo();
// this operator enables implicit Rcpp::wrap operator SEXP();
}
This is called \emph{intrusive} because the conversion to `SEXP` operator has to be declared within the class. ## Non-intrusive extension It is often desirable to offer automatic conversion to third-party types, over which the developer has no control and can therefore not include a conversion to `SEXP` operator in the class definition. To provide automatic conversion from \proglang{C++} to \proglang{R}, one must declare a specialization of the `Rcpp::wrap` template between the includes of `RcppCommon.h` and `Rcpp.h`. ```{Rcpp, eval = FALSE} #include <RcppCommon.h> // third party library that declares class Bar #include <foobar.h> // declaring the specialization namespace Rcpp { template <> SEXP wrap(const Bar&); } // this must appear after the specialization, // otherwise the specialization will not be // seen by Rcpp types #include <Rcpp.h>
It should be noted that only the declaration is required. The implementation
can appear after the Rcpp.h
file is included, and therefore take
full advantage of the \pkg{Rcpp} type system.
Another non-intrusive option is to expose an external pointer. The macro
RCPP_EXPORT_WRAP
provides an easy way to expose a \proglang{C++} class
to \proglang{R} as an external pointer. It can be used instead of specializing
Rcpp::wrap
, and should not be used simultaneously.
```{Rcpp, eval = FALSE}
RCPP_EXPORT_WRAP(Bar);
## Templates and partial specialization It is perfectly valid to declare a partial specialization for the `Rcpp::wrap` template. The compiler will identify the appropriate overload: ```{Rcpp, eval = FALSE} #include <RcppCommon.h> // third party library that declares // a template class Bling<T> #include <foobar.h> // declaring the partial specialization namespace Rcpp { namespace traits { template <typename T> SEXP wrap(const Bling<T>&); } } // this must appear after the specialization, or // specialization will not be seen by Rcpp types #include <Rcpp.h>
Rcpp::as
Conversion from \proglang{R} to \proglang{C++} is also possible in both intrusive and non-intrusive ways.
As part of its template meta programming dispatch logic, Rcpp::as
will attempt to use the constructor of the target class taking a SEXP
.
```{Rcpp, eval = FALSE}
class Foo{ public: Foo();
// this ctor enables implicit Rcpp::as Foo(SEXP);
}
// this must appear after the specialization, or // specialization will not be seen by Rcpp types
## Non-intrusive extension It is also possible to fully specialize `Rcpp::as` to enable non-intrusive implicit conversion capabilities. ```{Rcpp, eval = FALSE} #include <RcppCommon.h> // third party library that declares class Bar #include <foobar.h> // declaring the specialization namespace Rcpp { template <> Bar as(SEXP); } // this must appear after the specialization, or // specialization will not be seen by Rcpp types #include <Rcpp.h>
Furthermore, another non-intrusive option is to opt for sharing an R
external pointer. The macro RCPP_EXPORT_AS
provides an easy way to
extend Rcpp::as
to expose \proglang{R} external pointers to
\proglang{C++}. It can be used instead of specializing Rcpp::as
, and
should not be used simultaneously.
```{Rcpp, eval = FALSE}
RCPP_EXPORT_AS(Bar);
With this being said, there is one additional macro that can be used to simultaneously define both `Rcpp::wrap` and `Rcpp::as` specialization for an external pointer. The macro `RCPP_EXPOSED_CLASS` can be use to transparently exchange a class between \proglang{R} and \proglang{C++} as an external pointer. Do not simultaneously use it alongside `RCPP_EXPOSED_AS`, `RCPP_EXPOSED_WRAP`, `Rcpp::wrap`, or `Rcpp::as`. ## Templates and partial specialization The signature of `Rcpp::as` does not allow partial specialization. When exposing a templated class to `Rcpp::as`, the programmer must specialize the \pkg{Rcpp::traits::Exporter} template class. The TMP dispatch will recognize that a specialization of `Exporter` is available and delegate the conversion to this class. \pkg{Rcpp} defines the `Rcpp::traits::Exporter` template class as follows : ```{Rcpp, eval = FALSE} namespace Rcpp { namespace traits { template <typename T> class Exporter{ public: Exporter(SEXP x) : t(x){} inline T get() { return t; } private: T t; }; } }
This is the reason why the default behavior of Rcpp::as
is to
invoke the constructor of the type T
taking a SEXP
.
Since partial specialization of class templates is allowed, we can expose a set of classes as follows:
```{Rcpp, eval = FALSE}
// third party library that declares
// a template class Bling
// declaring the partial specialization
namespace Rcpp {
namespace traits {
template
// this must appear after the specialization, or // specialization will not be seen by Rcpp types
```
Using this approach, the requirements for the
Exporter< Bling<T> >
class are:
SEXP
get
that returns an instance
of the Bling<T>
type.The \pkg{Rcpp} package greatly facilitates the transfer of objects between
\proglang{R} and \proglang{C++}. This note has shown how to extend \pkg{Rcpp}
to either user-defined or third-party classes via the Rcpp::as
and
Rcpp::wrap
template functions. Both intrusive and non-intrusive
approaches were discussed.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.