Differences between cpp11 and Rcpp

Motivation

Vaughan, Hester, and Francois (2024) already provides some details. Here I will expand on the differences between cpp11 and Rcpp.

Read and write

In cpp11, when a variable is declared, it is read-only by default. This is different from Rcpp, where variables are read-write by default.

This code will not compile in cpp11:

[[cpp11::register]] integers square_coordinates_(integers x) {
  integers out = x;
  for (int i = 0; i < x.size(); ++i) {
    out[i] = x[i] * x[i];
  }
  return out;
}

The error message is:

code.cpp:515:10: error: lvalue required as left operand of assignment
  515 |     out[i] = x[i] * x[i];

To fix this, you need to explicitly declare the variable as writable:

[[cpp11::register]] integers square_coordinates_(integers x) {
  writable::integers out = x;
  for (int i = 0; i < x.size(); ++i) {
    out[i] = x[i] * x[i];
  }
  return out;
}

The arguments are also read-only by default in cpp11, unless you declare them as writable, as in the following example:

[[cpp11::register]] integers square_coordinates2_(writable::integers x) {
  for (int i = 0; i < x.size(); ++i) {
    x[i] = x[i] * x[i];
  }
  return x;
}

External pointers

In cpp11, you can use external_pointer. In Rcpp, you can use XPtr to create external pointers. These have a quite different syntax, and cpp11 does not provide an attr method for external pointers.

For example, the cpp11tesseract package defines:

typedef cpp11::external_pointer<tesseract::TessBaseAPI, tess_finalizer> TessPtr;

Then TessPtr is called with:

TessPtr ptr(api);
return ptr;

As a result, the R equivalent that the OCR C++ function verifies that the engine is such that the following is true:

stopifnot(inherits(engine, "externalptr"))

The equivalent tesseract package, that uses Rcpp, defines:

typedef Rcpp::XPtr<tesseract::TessBaseAPI, Rcpp::PreserveStorage, tess_finalizer, true> TessPtr;

Then TessPtr is called with:

TessPtr ptr(api);
ptr.attr("class") = Rcpp::CharacterVector::create("tesseract");
return ptr;

Similarly, the Rcpp version checks the engine with:

stopifnot(inherits(engine, "tesseract"))

References

Vaughan, Davis, Jim Hester, and Roman Francois. 2024. “Get Started with Cpp11.” https://cpp11.r-lib.org/articles/cpp11.html#intro.