Before you get started, the two rules of software optimization are (Jackson 1975):
You are all expert R programmers. So you should always begin in R.
When you move to C++, only do so in cases where it will help.
It helps when all three of the following occur:
The above is typically the only reason why you should switch. But as you get more advanced computational skills, you might switch to use data structures implemented in C++ like heaps or binary trees etc…
{Rcpp}
is a fantastic R package that makes integrating R and C++ almost painless.
In interactive mode, you can write a C++ function by using Rcpp::cppFunction()
. You put the source code in quotes.
R
::cppFunction(
Rcpp'
void hello_world() {
Rcpp::Rcout << "Hello World";
}
'
)
You can then use that funciton like you would any usual R function.
R
hello_world()
## Hello World
More frequently, you have a C++ file (ending in “.cpp”) that contains the following:
C++
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
void hello_world() {
::Rcout << "Hello World";
Rcpp}
Suppose this file is called “hello.cpp,” then you can load it into R using
R
::sourceCpp(file = "hello.cpp") Rcpp
and then use hello_world()
as you would any R function.
People almost never do either of these in practice. If you are using {Rcpp}
, it is almost always in an R package.
usethis::use_rcpp()
will automatically format an R package to have the appropriate structure for interfacing with {Rcpp}
.
You will have to include these lines in your documentation somewhere. I typically include them in the documentation for the package. Make sure you replace package_name
with the name of the package. Follow instructions from {usethis}
R
#' @useDynLib package_name, .registration = TRUE
#' @importFrom Rcpp sourceCpp
NULL
After running usethis::use_rcpp()
, it will
Add the following lines to your DESCRIPTION file:
LinkingTo:
Rcpp
Imports:
Rcpp
Create a src
directory.
You place all C++ files in the src
directory.
All C++ files end in “.cpp.”
Every file should generally begin with
C++
#include <Rcpp.h>
using namespace Rcpp;
The #include <Rcpp.h>
line basically makes Rcpp available to us in C++.
{Rcpp}
package in the Imports field of the DESCRIPTION folder. We now have access to the functions in from Rcpp.The using namespace Rcpp;
line brings the Rcpp namespace into scope so that we can use functions without declaring that they come from Rcpp. E.g., we can use Rcout
instead of Rcpp::Rcout
(just like importing a function in R).
C++ files should be entirely composed of functions (just like R scripts in packages).
A C++ function is of the form
C++
(arg1Type arg1, arg2Type arg2 = default2) {
ftype fname// code goes here
return retval;
}
ftype
is the type that is returned, such as int
or double
or Rcpp::NumericVector
, etc…
fname
is the function name that you choose.
arg1Type
and arg2Type
are the types of the arguments for the function.
One of these arguments, arg2
has a default value, default2
.
All C++ functions end with return
followed by the object that is being returned.
Notice that you don’t use assignment for creating C++ functions.
For example, here I return the sum of two integers:
C++
// [[Rcpp::export]]
int add2(int x, int y) {
int sum = x + y;
return sum;
}
R
add2(1, 2)
## [1] 3
Comments in C++ are //
, not #
.
If you want R to have access to an C++ function, you must include the exact line right above the function:
C++
// [[Rcpp::export]]
If you don’t include this, it will still be available to your other C++ functions, but not to R.
You document C++ functions exactly like R code, except you begin {roxygen2}
lines with //'
.
C++
//' @title Add two integers
//'
//' @param x Integer 1
//' @param y Integer 2
//'
//' @return Their sum
//'
//' @author David Gerard
// [[Rcpp::export]]
int add2(int x, int y) {
int sum = x + y;
return sum;
}
The workflow for working with Rcpp is:
devtools::load_all()
to compile the function and load it into memory.
devtools::document()
if you changed the documentation.