- 1
-
We include the header using
<Rcpp.h>, not"Rcpp.h". - 2
-
This is to avoid typing
Rcpp::before every object. - 3
- This is a comment that tells Rcpp to export this function to R.
- 4
- Create a vector of the same size as x.
Intro to Rcpp
PHS 7045: Advanced Programming
Intro
Before we start
You need to have Rcpp installed in your system:
install.packages("Rcpp")You need to have a compiler
And that’s it!
R is great, but…
The problem:
As we saw, R is very fast… once vectorized
What to do if your model cannot be vectorized?
The solution: Use C/C++/Fotran! It works with R!
The problem to the solution: What R user knows any of those!?
R has had an API (application programming interface) for integrating C/C++ code with R for a long time.
Unfortunately, it is not very straightforward
Enter Rcpp
One of the most important R packages on CRAN.
As of July 17, 2024, about 60% of CRAN packages depend on it (directly or not).
From the package description:
The ‘Rcpp’ package provides R functions as well as C++ classes which offer a seamless integration of R and C++
Why bother?
To draw ten numbers from a normal distribution with sd = 100.0 using R C API:
SEXP stats = PROTECT(R_FindNamespace(mkString("stats"))); SEXP rnorm = PROTECT(findVarInFrame(stats, install("rnorm"))); SEXP call = PROTECT( LCONS( rnorm, CONS(ScalarInteger(10), CONS(ScalarReal(100.0), R_NilValue)))); SET_TAG(CDDR(call),install("sd")); SEXP res = PROTECT(eval(call, R_GlobalEnv)); UNPROTECT(4); return res;Using Rcpp:
Environment stats("package:stats"); Function rnorm = stats["rnorm"]; return rnorm(10, Named("sd", 100.0));
The Rcpp ecosystem
Rcpp (link): The main API that exposes C++ to R.
RcppArmadillo (link): A package that provides a high-level interface to the Armadillo C++ library for linear algebra (great for sparse matrices).
RcppEigen (link): A package that provides a high-level interface to the Eigen C++ library for linear algebra (great for file-backed matrices).
RcppParallel (link) and RcppThread (link): Packages that provide parallel computing capabilities.
You can find execellent examples using Rcpp in https://gallery.rcpp.org.
There’s also the
cpp11package (we won’t cover it in this course).
Example 1: Looping over a vector
add1(1:10) [1] 2 3 4 5 6 7 8 9 10 11
Example 1: Looping over a vector (vers 2)
Make it sweeter by adding some “sugar” (the Rcpp kind)
#include<Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
NumericVector add1Cpp(NumericVector x) {
return x + 1;
}add1Cpp(1:10) [1] 2 3 4 5 6 7 8 9 10 11
How much fast?
Compared to this:
add1R <- function(x) {
for (i in 1:length(x))
x[i] <- x[i] + 1
x
}
microbenchmark::microbenchmark(add1R(1:1000), add1Cpp(1:1000))Unit: microseconds
expr min lq mean median uq max neval
add1R(1:1000) 57.587 59.6665 86.24994 60.0120 60.443 2579.868 100
add1Cpp(1:1000) 3.646 4.0470 11.53178 4.2125 4.413 729.730 100
Obviously vectorization in R would be faster, but this is just an example.
C++ in R
Main differences between R and C++
One is compiled, and the other interpreted
Indexing objects: In C++ the indices range from 0 to
(n - 1), whereas in R is from 1 ton.All expressions end with a
;(optional in R).In C++ object need to be declared, in R not (dynamic).
C++/Rcpp fundamentals: Types
Besides C-like data types (double, int, char, and bool), we can use the following types of objects with Rcpp:
Matrices:
NumericMatrix,IntegerMatrix,LogicalMatrix,CharacterMatrixVectors:
NumericVector,IntegerVector,LogicalVector,CharacterVectorAnd more!:
DataFrame,List,Function,Environment
Parts of “an Rcpp program”
- 1
-
The
#include<Rcpp.h> is similar tolibrary(...)in R, it brings in all that we need to write C++ code for Rcpp. - 2
-
using namespace Rcpp is somewhat similar todetach(...). This simplifies syntax. If we don’t include this, all calls to Rcpp members need to be explicit, e.g., instead of typingNumericVector, we would need to typeRcpp::NumericVector - 3
-
The
//starts a comment in C++, in this case, the// [[Rcpp::export]] comment is a flag Rcpp uses to “export” this C++ function to R. - 4
-
It is the first part of the function definition. We are creating a function that returns a
NumericVector , is calledadd1 , has a single input element namedx that is also aNumericVector .
Parts of “an Rcpp program” (cont’d)
- 5
-
Here, we are declaring an object called
ans , which is aNumericVector with an initial size equal to the size ofx . Notice that.size() is called a “member function” of thexobject, which is of classNumericVector. - 6
- We are declaring a for-loop (three parts):
- 7
-
ans[i] = x[i] + 1 set the i-th element ofansequal to the i-th element ofxplus 1. - 8
-
return ans exists the function returning the vectorans.
C++/Rcpp fundamentals
Now, where to execute/run this?
- You can use the
sourceCppfunction from theRcpppackage to run .cpp scripts (this is what I do most of the time).
- There’s also
cppFunction, which allows compiling a single function.
- Write an R package that works with Rcpp.
For now, let’s use the first option.
Example running .cpp file
Using the norm.cpp file (which you can download):
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
double normRcpp(NumericVector x) {
return sqrt(sum(pow(x, 2.0)));
}We can compile and obtain this function using this line Rcpp::sourceCpp("norm.cpp"):
Rcpp::sourceCpp("norm.cpp")
normRcpp(1:10)[1] 19.62142
sqrt(sum((1:10)^2))[1] 19.62142
Examlpe running .cpp file (cont’d)
Let’s do it again but see the verbose output:
Rcpp::sourceCpp("norm.cpp", verbose = TRUE)
No rebuild required (use rebuild = TRUE to force a rebuild)
Your turn
Now, get ready for some Rcpp action!

Problem 1: Adding vectors
- Using what you have just learned about Rcpp, write a function to add two vectors of the same length. Use the following template
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
NumericVector add_vectors([declare vector 1], [declare vector 2]) {
... magick ...
return [something];
}- Now, we have to check for lengths. Use the
stopfunction to make sure lengths match. Add the following lines in your code
if ([some condition])
stop("an arbitrary error message :)");Problem 2: Fibonacci series

Each element of the sequence is determined by the following:
\[ F(n) = \left\{\begin{array}{ll} n, & \mbox{ if }n \leq 1\\ F(n - 1) + F(n - 2), & \mbox{otherwise} \end{array}\right. \]
Using recursions, we can implement this algorithm in R as follows:
fibR <- function(n) {
if (n <= 1)
return(n)
fibR(n - 1) + fibR(n - 2)
}
# Is it working?
c(
fibR(0), fibR(1), fibR(2),
fibR(3), fibR(4), fibR(5),
fibR(6)
)[1] 0 1 1 2 3 5 8
Now, let’s translate this code into Rcpp and see how much speed boost we get!
Problem 2: Fibonacci series (solution)
Here is the full solution (hidden!):
Code
#include <Rcpp.h>
// [[Rcpp::export]]
int fibCpp(int n) {
if (n <= 1)
return n;
return fibCpp(n - 1) + fibCpp(n - 2);
}microbenchmark::microbenchmark(fibR(20), fibCpp(20))Unit: microseconds
expr min lq mean median uq max neval
fibR(20) 6144.581 6197.27 6521.29757 6246.0005 6378.398 8584.429 100
fibCpp(20) 15.729 16.15 32.64678 21.7405 25.327 1078.620 100
Exposing C++ classes to R
Exposing C++ classes to R
#include <Rcpp.h>
class Person {
public:
Person(std::string name, int age) :
name(name), age(age) {}
std::string get_name() const { return name; }
int get_age() const { return age; }
void print() const {Rprintf(
"%s is %d years old\n", name.c_str(), age);
}
private:
std::string name;
int age;
};
// [[Rcpp::export]]
Rcpp::XPtr<Person> create_person(
std::string name, int age
) {
return Rcpp::XPtr<Person>(new Person(name, age));
}
// [[Rcpp::export]]
std::string get_name(SEXP person) {
Rcpp::XPtr<Person> p(person);
return p->get_name();
}
// [[Rcpp::export]]
int print_person(SEXP person) {
Rcpp::XPtr<Person> p(person);
p->print();
return 0;
}- We define a class
Personwith a constructor, three methods, and two private members.
- The print method uses
Rprintfto print to the R console.
- (Wrapping the class) The
create_personfunction creates a pointer (wrapper) to aPersonobject (XPtr<Person>). Notice thenewkeyword.
- (Unwrapping the class) To unwrap the class, we use the
XPtrconstructor on anSEXPobject (S expression, from when R was called S!). We use->to access the class methods.
Now let’s use it!
Exposing C++ classes to R (cont’d)
# Construct a person
myperson <- create_person("Jorge", 30)
# Get the name
get_name(myperson)
## [1] "Jorge"
# Default print is not very informative
myperson
## <pointer: 0x560e9f241370>
print_person(myperson) # Custom print
## Jorge is 30 years old
## [1] 0Fin
devtools::session_info()─ Session info ───────────────────────────────────────────────────────────────
setting value
version R version 4.5.3 (2026-03-11)
os Ubuntu 24.04.4 LTS
system x86_64, linux-gnu
ui X11
language (EN)
collate en_US.UTF-8
ctype en_US.UTF-8
tz Etc/UTC
date 2026-09-08
pandoc 3.9 @ /usr/bin/ (via rmarkdown)
quarto 1.9.35 @ /usr/local/bin/quarto
─ Packages ───────────────────────────────────────────────────────────────────
package * version date (UTC) lib source
cachem 1.1.0 2024-05-16 [1] RSPM
cli 3.6.5 2025-04-23 [1] RSPM
codetools 0.2-20 2024-03-31 [2] CRAN (R 4.5.3)
devtools 2.4.6 2025-10-03 [1] RSPM
digest 0.6.39 2025-11-19 [1] RSPM
ellipsis 0.3.2 2021-04-29 [1] RSPM
evaluate 1.0.5 2025-08-27 [1] RSPM
fastmap 1.2.0 2024-05-15 [1] RSPM
fs 1.6.7 2026-03-06 [1] RSPM
glue 1.8.0 2024-09-30 [1] RSPM
htmltools 0.5.9 2025-12-04 [1] RSPM
htmlwidgets 1.6.4 2023-12-06 [1] RSPM
jsonlite 2.0.0 2025-03-27 [1] RSPM
knitr 1.51 2025-12-20 [1] RSPM
lifecycle 1.0.5 2026-01-08 [1] RSPM
magrittr 2.0.4 2025-09-12 [1] RSPM
memoise 2.0.1 2021-11-26 [1] RSPM
microbenchmark 1.5.0 2024-09-04 [1] RSPM (R 4.5.0)
otel 0.2.0 2025-08-29 [1] RSPM
pkgbuild 1.4.8 2025-05-26 [1] RSPM
pkgload 1.5.0 2026-02-03 [1] RSPM
purrr 1.2.1 2026-01-09 [1] RSPM
R6 2.6.1 2025-02-15 [1] RSPM
Rcpp 1.1.1 2026-01-10 [1] RSPM
remotes 2.5.0 2024-03-17 [1] RSPM
rlang 1.1.7 2026-01-09 [1] RSPM
rmarkdown 2.30 2025-09-28 [1] RSPM
sessioninfo 1.2.3 2025-02-05 [1] RSPM
usethis 3.2.1 2025-09-06 [1] RSPM
vctrs 0.7.1 2026-01-23 [1] RSPM
xfun 0.56 2026-01-18 [1] RSPM
yaml 2.3.12 2025-12-10 [1] RSPM
[1] /usr/local/lib/R/site-library
[2] /usr/local/lib/R/library
──────────────────────────────────────────────────────────────────────────────

