vignettes/rmd/Rcpp-extending.Rmd
Rcpp-extending.RmdAbstract
This note provides an overview of the steps programmers should follow to extend for use with their own classes. This document is based on our experience in extending to work with the classes, available in the separate package . This document assumes knowledge of as well as some knowledge of templates .
facilitates data interchange between and through the templated
functions Rcpp::as (for conversion of objects from to ) and
Rcpp::wrap (for conversion from to ). In other words, we
convert between the so-called -expression pointers (in type
SEXP) to a templated type, and vice versa. The
corresponding function declarations are as follows:
// conversion from R to C++
template <typename T> T as(SEXP x);
// conversion from C++ to R
template <typename T> SEXP wrap(const T& object);These converters are often used implicitly, as in the following code chunk:
#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)## $front
## [1] 1
##
## $back
## [1] 10
The converter functions Rcpp::as and
Rcpp::wrap are extensible to user-defined types and
third-party types.
Rcpp::wrap
The converter is extensible in essentially two ways : intrusive and non-intrusive.
When extending 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.
#include <RcppCommon.h>
class Foo {
public:
Foo();
// this operator enables implicit Rcpp::wrap
operator SEXP();
}
#include <Rcpp.h>This is called because the conversion to SEXP operator
has to be declared within the class.
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 to , one must declare a
specialization of the Rcpp::wrap template between the
includes of RcppCommon.h and Rcpp.h.
#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 type system.
Another non-intrusive option is to expose an external pointer. The
macro RCPP_EXPOSED_WRAP provides an easy way to expose a
class to as an external pointer. It can be used instead of specializing
Rcpp::wrap, and should not be used simultaneously. Note
that the class has to use Rcpp modules. See the Rcpp modules vignette
for more details.
It is perfectly valid to declare a partial specialization for the
Rcpp::wrap template. The compiler will identify the
appropriate overload:
#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 to 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.
It is also possible to fully specialize Rcpp::as to
enable non-intrusive implicit conversion capabilities.
#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_EXPOSED_AS provides an
easy way to extend Rcpp::as to expose external pointers to
. It can be used instead of specializing Rcpp::as, and
should not be used simultaneously. Note that the class has to use Rcpp
modules. See the Rcpp modules vignette for more details.
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 and as an external pointer. Do not simultaneously use it
alongside RCPP_EXPOSED_AS, RCPP_EXPOSED_WRAP,
Rcpp::wrap, or Rcpp::as.
The signature of Rcpp::as does not allow partial
specialization. When exposing a templated class to
Rcpp::as, the programmer must specialize the template
class. The TMP dispatch will recognize that a specialization of
Exporter is available and delegate the conversion to this
class. defines the Rcpp::traits::Exporter template class as
follows :
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:
#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>
class Exporter< Bling<T> >;
}
}
// this must appear after the specialization, or
// specialization will not be seen by Rcpp types
#include <Rcpp.h>Using this approach, the requirements for the
Exporter< Bling<T> > class are:
SEXP
get that returns an
instance of the Bling<T> type.