Skip to contents

What is Rcpp

Definition

Rcpp is an R package that facilitates seamless integration of R and C++ code. By providing tools and classes within this R package, users can easily write high-performance C++ functions and use them directly in R, which allows users to combine R’s statistical capabilities with the speed and flexibility of C++.

Rcpp acts as an Application Programming Interface (API) between R and C++. As an API, Rcpp defines a set of tools and conventions that enable R and C++ code to communicate and work together seamlessly, making it easy to call C++ functions from R and exchange data between the two languages.

Why use Rcpp

There are other options out there besides Rcpp, e.g., cpp11 and cpp4r. We choose to use Rcpp because

  • Rcpp is one of the most widely used R extensions (i.e., over 1000 packages),
  • With very minimal knowledge of C++, Rcpp facilitates increasing the speed of functions, and
  • The most efficient R functions are written in C++ and called from R.

Writing C++ functions

Inline C++ code in R

Using {Rcpp} you can compile C++ code using R and never have to interact with an external file or compiler using one of the two following functions:

  • You can write C++ functions inline in your R code by wrapping the C++ code in Rcpp::cppFunction().
  • You can compile and execute single lines of code directly using Rcpp::evalCpp().
Example: Inline C++ within R
library(Rcpp)

# Compile inline C++ using R
Rcpp::cppFunction("int add(int x, int y, int z) {
  int sum = x + y + z;
  return sum;
}")

# after compiling, add works like a regular R function
add
## function (x, y, z) 
## .Call(<pointer: 0x7f510d7d5530>, x, y, z)
add(1, 2, 3)
## [1] 6
# Compile and execute C++ code
# Find the square root of 16
Rcpp::evalCpp("std::sqrt(16.0)")
## [1] 4
# Return the largest representable double value
Rcpp::evalCpp("std::numeric_limits<double>::max()")
## [1] 1.797693e+308

Calling .cpp files from R

You can save your C++ code in a separate file with the .cpp extension and call this file from R using Rcpp::sourceCpp(). For example, the code below stores meanC, a C++ function that calculates the mean of a numeric vector. This code can be saved in a .cpp file, e.g., mean.cpp and compiled within your R session with Rcpp::sourceCpp("mean.cpp"). Again, if you do not want to use external cpp files, you can wrap the C++ code in quotes and store it as an R object like the example above. Either way, the C++ is then made available within the R session using Rcpp::sourceCpp(). Both methods are illustrated below.

Example: mean.cpp
/*
 The include statement allows you to use the Rcpp library in Rcpp.h, which
 includes NumericVector.
*/
#include <Rcpp.h>
/*
 You can use Rcpp functions like NumericVector without specifying their
 namespace on each instance if you include the  entire Rcpp namespace using the
 line below, e.g., you can use `NumericVector` rather than
 `Rcpp::NumericVector`.
*/
using namespace Rcpp;

/*
 Use Rcpp::export to export the following function to R
*/
// [[Rcpp::export]]
double meanC(NumericVector x) {
  /*
   .size() is a member function of Rcpp::NumericVector class and can be accessed
   with the dot operator from any Rcpp::NumericVector object
  */
  int n = x.size();
  double total = 0;

  for (int i = 0; i < n; ++i) {
    /*
     += is the same as x = x + y, and is known as an overload operator
    */
    total += x[i];
  }
  return total / n;
}
Example: Sourcing C++ Code in R
# code can be saved in .cpp file and compiled
# Rcpp::sourceCpp("mean.cpp")
# meanC(1:10)

# The same code that is stored in mean.cpp can be sourced directly
src <-
  "#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
double meanC(NumericVector x) {
  int n = x.size();
  double total = 0;

  for (int i = 0; i < n; ++i) {
    total += x[i];
  }
  return total / n;
}
"
# compile the text
Rcpp::sourceCpp(code = src)
meanC(1:10)
## [1] 5.5

Benchmarking against R

Compiled C++ is often much faster than R. Below we compare our compiled meanC function against the R function mean using {microbenchmark}.

Example: Benchmarking R vs C++
library(microbenchmark)
x <- runif(1e5)
microbenchmark(
  mean(x),
  meanC(x)
)
## Unit: microseconds
##      expr     min       lq     mean   median      uq       max neval
##   mean(x) 421.977 431.5345 438.8228 436.0435 443.242   522.274   100
##  meanC(x) 371.943 372.6955 491.9060 375.0845 381.451 11743.380   100

C++ in FIMS

In FIMS, most of the C++ code is organized into several header files that are stored in the inst/include/ directory. These files include the definitions of Rcpp modules and interfaces (in inst/include/interface/rcpp/*) that make C++ classes and functions accessible from R.

A single C++ source file (i.e., src/FIMS.cpp) lists all of the header files and serves as their main entry point for compilation. The build process is managed by the src/Makevars file (and src/Makevars.win for Windows machines), which sets the necessary compiler and linker flags for R to compile the C++ code into a shared library (DLL or SO). This shared library is automatically loaded by R when users call library(FIMS), allowing R users to call high-performance C++ code without needing to use Rcpp::sourceCpp() manually.

Rcpp Types

Rcpp types map standard C++ data types to R objects enabling seamless data exchange and operations between R and C++ for efficiency. Example Rcpp types include classes like NumericVector and IntegerVector. Rcpp types handle everything from basic data to complex structures like matrices, lists, and functions. Additionally, each type handles memory management for you automatically.

Rcpp scalar classes

  • Integer: int
  • Double: double
  • Boolean: bool
  • String: String

Rcpp vector classes

  • Vector of integers: IntegerVector
  • Vector of doubles: NumericVector
  • Vector of booleans: LogicalVector
  • Vector of strings: CharacterVector

SEXP in R

Under the hood, every R object—whether it’s a number, vector, list, or function—is represented in C code as a SEXP (S-expression). A SEXP is essentially a pointer (see the section on pointers in the C++ vignette) to a data structure called a SEXPREC. The SEXPREC structure contains information about the type of the object (such as numeric, integer, logical, or character), as well as the actual data and other metadata. This design allows R to handle all its objects in a uniform way, regardless of their specific type. See the SEXP Structures in C for more information.

When you use Rcpp types like NumericVector, Rcpp automatically manages the conversion between these internal R representations and C++ types, so you usually don’t need to interact with SEXP directly. However, when writing more advanced C++ code or working with the R API at a low level, you may encounter SEXP types explicitly.

Type conversion

When working with C++ code that doesn’t use Rcpp types directly, you can use wrap() and as<>() to convert between R objects (SEXP) and C++ types.

  • as<>(): Converts R objects (SEXP) to C++ types
  • wrap(): Converts C++ types to R objects (SEXP)

These functions are particularly useful when you want to use standard C++ types (like std::vector<double>) in your C++ code while still maintaining compatibility with R. See get_report() in rcpp_models.hpp for an example of as<>().

Example: Using wrap and as
#include <Rcpp.h>
using namespace Rcpp;

template <typename T>
T meanC(std::vector<T> x) {
  int n = x.size();
  T total = 0;
  
  for(int i = 0; i < n; ++i) {
    total += x[i];
  }
  return total / n;
}

// [[Rcpp::export]]
SEXP mean_wrap(SEXP input){
  // Convert R object to C++ std::vector
  std::vector<double> x = as<std::vector<double>>(input);
  
  // Perform calculation
  double mean = meanC(x);
  
  // Convert C++ result back to R object
  return wrap(mean);
}

Rcpp methods

Rcpp methods are functions that belong to Rcpp classes and allow you to interact with C++ objects from R in an object-oriented way.

  • Static methods are called using :: on a class. For example, NumericVector::create() creates a numeric vector without needing an existing object.
  • Member methods (or member functions) are called on specific objects using the $ operator in R and the dot operator in C++. For example, the .size() member function of the NumericVector class returns the number of elements in the Rcpp::NumericVector class. If you have any experience with Python, it’s somewhat similar to the way you use dot notation there.
Example: Rcpp Vectors and Methods
src <-
  "#include <Rcpp.h>
  using namespace Rcpp;

  // [[Rcpp::export]]
  NumericVector fun() {
    //Call static methods on NumericVector
    //Create new vector of size 3 using numbers 1, 2, and 3
    NumericVector v = NumericVector::create(1, 2, 3);
    Rcout << NumericVector::get_na() << std::endl;

    //Call member methods on object v of class NumericVector
    //Print the length of v
    Rcout << v.size() << std::endl;
    //append the number 4 to the vector using push_back()
    v.push_back(4);

    return v;
  }
"

# Compile the code and call it
sourceCpp(code = src)
fun()
## nan
## 3
## [1] 1 2 3 4

Rcpp modules

Rcpp modules are a feature of the Rcpp package that allow you to expose C++ classes, methods, and functions to R in a structured and object-oriented way. This makes it possible to work with C++ objects directly from R, enabling more advanced and efficient workflows that combine the strengths of both languages. A module is defined in C++ using the RCPP_MODULE macro.

By using modules, you avoid the need to write low-level interface code for each function or class you want to expose. Instead, you describe the interface in a concise and readable way, and Rcpp handles the details of data conversion and method dispatch.

RCPP_MODULE

Rcpp modules can be used to expose C++ functions and classes using the Rcpp macro RCPP_MODULE. Without RCPP_MODULE the C++ that you want to call within R would have to be extremely complex to work within the R environment. Much of the complexity of changing R input (SEXP) into C++ types is handled by including #include <Rcpp.h> but RCPP_MODULE handles some additional complexity.

Within a module, you can register the following components:

  • Constructors: These specify how to create new instances of a C++ class from R, mapping R arguments to C++ constructors.
  • Fields: These are member variables of a class that you want to make accessible from R. You can expose them as read/write or read-only.
  • Methods: These are member functions of a class that can be called from R, allowing you to invoke C++ logic on your objects.
  • Properties: These are similar to fields but can have custom getter and setter functions, providing more control over how R interacts with the underlying C++ data.

Thus, RCPP_MODULEs can include .field, .constructor, .method, and .property arguments, where .field can be used with two or three arguments. For example, the class that we create below called Uniform is complex with a constructor; two inputs, min and max; and one method, draw. Additionally, classes can include .field_readonly, which prevents it from being modified within R.

Example: Complete Uniform Class with Module

First, we define a C++ class for generating uniform random numbers:

#include <Rcpp.h>
using namespace Rcpp;

class Uniform {
public:
  Uniform(double min_, double max_) :
  min(min_), max(max_) {}
  
  NumericVector draw(int n) {
    RNGScope scope;
    return runif(n, min, max);
  }

  double min, max;
};

Then we expose this class to R using RCPP_MODULE:

RCPP_MODULE(unif_module) {
  class_<Uniform>("Uniform")
  .constructor<double,double>()
  .field("min", &Uniform::min, "minimum value")
  .field("max", &Uniform::max, "maximum value")
  .method("draw", &Uniform::draw);
}

After compiling with Rcpp::sourceCpp(), you can use this class from R:

# Create a new Uniform object
u <- new(Uniform, 0, 10)

# Call methods and access fields
u$draw(10L)
u$max
u$max <- 5
u$draw(10)

RCPP_EXPOSED_CLASS

Rcpp provides several built-in types, such as Rcpp::NumericVector, but when you define your own C++ class, you need to make Rcpp aware of it. This is done using the RCPP_EXPOSED_CLASS macro. For example, if you create a new class called FancyVector, you need add RCPP_EXPOSED_CLASS(FancyVector) to your code. This macro instructs Rcpp to generate the necessary type information, allowing your new class to be used within Rcpp modules. As a result, you can pass objects of your class between R and C++, store them in Rcpp containers, and use them as arguments or return values in Rcpp-exposed functions.

Modules in FIMS

Within FIMS, we first use RCPP_EXPOSED_CLASS() to expose all of our new type classes, e.g., RCPP_EXPOSED_CLASS(Parameter) in src/fims_modules.hpp. Once all of the type classes are exposed, we then use a single instance of RCPP_MODULE to expose the C++ to R in that same file.