Skip to content

Instantly share code, notes, and snippets.

@romainfrancois
Created May 22, 2014 09:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save romainfrancois/010fe19cdb34c624c7f4 to your computer and use it in GitHub Desktop.
Save romainfrancois/010fe19cdb34c624c7f4 to your computer and use it in GitHub Desktop.
Extending wrap in Rcpp11

Context

Extending wrap to custom classes has always been a struggle in Rcpp, and led to the split between RcppCommon.h and Rcpp.h, the idea being that you load a "minimal" subset of Rcpp, declare your class, declare that you are going to provide a specialization of wrap, load the rest of Rcpp (the meat), and finally define your specialization.

Let's consider this template class :

template <typename T>
class MyType {} ;

it does nothing, I'm just using it to illustrate the point. Extending wrap for such a template will allow us to write functions like this:

// [[Rcpp::export]]
MyType<double> test(){
  return MyType<double>() ;
}

Attributes will generate code that uses wrap internally. So all we have to do is write this special wrap. The simplest way is for classes that have an operator SEXP but for the purpose of this post, let's just consider it does not and that we can't make modifications to the class.

implement wrap with Rcpp

In Rcpp, here is what it takes to implement wrap for it (according to the extending vignette).

// first include the minimal set of Rcpp functionality
#include <RcppCommon.h>

// declare our type
template <typename T>
class MyType {} ;

// declare that we will later specialize wrap
namespace Rcpp{
    
    template <typename T>
    inline SEXP wrap( const MyType<T>& obj ) ;
    
} 

// include the rest
#include <Rcpp.h>

// and finally define the overload
namespace Rcpp{
    template <typename T>
    inline SEXP wrap( const MyType<T>& obj ) {
        return IntegerVector::create( 1, 2 ) ;        
    }
}

This has been the basis for packages like RcppArmadillo, etc ... and it requires lots of care. The definition of our wrap must be after we include Rcpp.h because we need IntegerVector::create, inclusion of Rcpp.h so that all uses of wrap know about our specialization, the declaration of our specialization must be after RcppCommon.h because that's where we declare the general wrap.

That's a lot to stomach.

implement wrap in Rcpp11

In Rcpp11 the RcppCommon.h does not exist and specializing wrap is simpler:

// include all Rcpp11 headers all at once
#include <Rcpp.h>

// our template class
template <typename T>
class MyType {} ;

// specialization of the Wrapper template for it. 
namespace Rcpp{
    
    template <typename T>
    struct Wrapper< MyType<T> > {
        static inline SEXP wrap( const MyType<T>& obj ){
            return IntegerVector::create( 1, 2 ) ;    
        }
    } ;
} 

All we have to do is write specializations of the Wrapper template class. This is much simpler.

#include <RcppCommon.h>
template <typename T>
class MyType {} ;
namespace Rcpp{
template <typename T>
inline SEXP wrap( const MyType<T>& obj ) ;
}
#include <Rcpp.h>
namespace Rcpp{
template <typename T>
inline SEXP wrap( const MyType<T>& obj ) {
return IntegerVector::create( 1, 2 ) ;
}
}
// [[Rcpp::export]]
MyType<double> test(){
return MyType<double>() ;
}
/*** R
test()
*/
#include <Rcpp.h>
template <typename T>
class MyType {} ;
namespace Rcpp{
template <typename T>
struct Wrapper< MyType<T> > {
static inline SEXP wrap( const MyType<T>& obj ){
return IntegerVector::create( 1, 2 ) ;
}
} ;
}
// [[Rcpp::export]]
MyType<double>( test(){
return MyType<double>() ;
}
/*** R
test()
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment