You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
## Incomplete list of Rcpp features not included in cpp11
49
-
50
-
- None of [Modules](https://CRAN.R-project.org/package=Rcpp/vignettes/Rcpp-modules.pdf)
51
-
- None of [Sugar](https://CRAN.R-project.org/package=Rcpp/vignettes/Rcpp-sugar.pdf)
52
-
- Some parts of [Attributes](https://CRAN.R-project.org/package=Rcpp/vignettes/Rcpp-attributes.pdf)
53
-
- No dependencies
54
-
- No random number generator restoration
55
-
- No support for roxygen2 comments
56
-
- No interfaces
25
+
## Getting started
26
+
27
+
1. Add cpp11 by calling `usethis::use_cpp11()`.
28
+
29
+
1. Start converting function by function.
30
+
31
+
Converting the code a bit at a time (and regularly running your tests) is the best way to do the conversion correctly and make progress. Doing a separate commit after converting each file (or possibly each function) can make finding any regressions with [git bisect](https://youtu.be/KKeucpfAuuA) much easier in the future.
32
+
33
+
1. Convert `#include <Rcpp.h>` to `#include <cpp11.hpp>`.
34
+
1. Convert all instances of `// [[Rcpp::export]]` to `[[cpp11::register]]`.
35
+
1. Grep for `Rcpp::` and replace with the equivalent cpp11 function using the cheatsheets below.
36
+
37
+
1. Remove Rcpp
38
+
1. Remove Rcpp from the `LinkingTo` and `Imports` fields.
39
+
1. Remove `@importFrom Rcpp sourceCpp`.
40
+
1. Delete `src/RccpExports.cpp` and `R/RcppExports.R`.
41
+
1. Delete `src/Makevars` if it only contains `PKG_CPPFLAGS=-DSTRICT_R_HEADERS`.
42
+
1. Clean out old compiled code with `pkgbuild::clean_dll()`.
43
+
1. Re-document the package to update the `NAMESPACE`.
Note that each cpp11 vector class has a read-only and writeable version.
61
+
The default classes, e.g. `cpp11::doubles` are *read-only* classes that do not permit modification.
62
+
If you want to modify the data you or create a new vector, use the writeable variant.
57
63
58
-
## Read-only vs writable vectors
64
+
Another major difference in Rcpp and cpp11 is how vectors are grown.
65
+
Rcpp vectors have a `push_back()` method, but unlike `std::vector()` no additional space is reserved when pushing.
66
+
This makes calling `push_back()` repeatably very expensive, as the entire vector has to be copied each call.
67
+
In contrast `cpp11` vectors grow efficiently, reserving extra space.
68
+
See <https://cpp11.r-lib.org/articles/motivations.html#growing-vectors> for more details.
59
69
60
-
The largest difference between cpp11 and Rcpp classes is that Rcpp classes modify their data in place, whereas cpp11 classes require copying the data to a writable class for modification.
70
+
Rcpp also allows very flexible implicit conversions, e.g. if you pass a `REALSXP` to a function that takes a `Rcpp::IntegerVector()` it is implicitly converted to a `INTSXP`.
71
+
These conversions are nice for usability, but require (implicit) duplication of the data, with the associated runtime costs.
72
+
cpp11 throws an error in these cases. If you want the implicit coercions you can add a call to `as.integer()` or `as.double()` as appropriate from R when you call the function.
61
73
62
-
The default classes, e.g. `cpp11::doubles` are *read-only* classes that do not permit modification.
63
-
If you want to modify the data you need to use the classes in the `cpp11::writable` namespace, e.g. `cpp11::writable::doubles`.
74
+
### Other objects
64
75
65
-
In addition use the `writable` variants if you need to create a new R vector entirely in C++.
76
+
| Rcpp | cpp11 |
77
+
| --- | --- |
78
+
| XPtr | external_pointer |
79
+
| Environment | environment |
80
+
| Function | function |
81
+
| Environment (namespace) | package |
66
82
67
-
##Fewer implicit conversions
83
+
### Functions
68
84
69
-
Rcpp also allows very flexible implicit conversions, e.g. if you pass a `REALSXP` to a function that takes a `Rcpp::IntegerVector()` it is implicitly converted to a `INTSXP`.
70
-
These conversions are nice for usability, but require (implicit) duplication of the data, with the associated runtime costs.
cpp11 throws an error in these cases. If you want the implicit coercions you can add a call to `as.integer()` or `as.double()` as appropriate from R when you call the function.
93
+
Note that `cpp11::stop()` and `cpp11::warning()` are thin wrappers around `Rf_stop()` and `Rf_warning()`.
94
+
These are simple C functions with a `printf()` API, so they do not understand C++ objects like `std::string`.
95
+
Therefore you need to call `obj.c_str()` when passing string data to them.
73
96
74
-
##Calling R functions from C++
97
+
### R functions
75
98
76
99
Calling R functions from C++ is similar to using Rcpp.
One major difference in Rcpp and cpp11 is how vectors are grown.
94
-
Rcpp vectors have a `push_back()` method, but unlike `std::vector()` no additional space is reserved when pushing.
95
-
This makes calling `push_back()` repeatably very expensive, as the entire vector has to be copied each call.
96
-
97
-
In contrast `cpp11` vectors grow efficiently, reserving extra space.
98
-
Because of this you can do ~10,000,000 vector appends with cpp11 in approximately the same amount of time that Rcpp does 10,000, as this benchmark demonstrates.
labs(title = "log-log plot of vector size vs construction time", x = NULL, y = NULL)
132
-
```
133
-
134
-
```{r, echo = FALSE}
135
-
knitr::kable(b_grow)
136
-
```
115
+
- None of [Modules](https://CRAN.R-project.org/package=Rcpp/vignettes/Rcpp-modules.pdf)
116
+
- None of [Sugar](https://CRAN.R-project.org/package=Rcpp/vignettes/Rcpp-sugar.pdf)
117
+
- Some parts of [Attributes](https://CRAN.R-project.org/package=Rcpp/vignettes/Rcpp-attributes.pdf)
118
+
- No dependencies
119
+
- No random number generator restoration
120
+
- No support for roxygen2 comments
121
+
- No interfaces
137
122
138
-
##Random Number behavior
123
+
### RNGs
139
124
140
-
Rcpp unconditionally includes calls to `GetRNGstate()` and `PutRNGstate()`before each wrapped function.
141
-
This ensures that if any C++ code calls the R API functions `unif_rand()`, `norm_rand()`, `exp_rand()` or `R_unif_index()` the random seed state is set accordingly.
125
+
Rcpp includes calls to `GetRNGstate()` and `PutRNGstate()` around the wrapped function.
126
+
This ensures that if any C++ code calls the R API functions `unif_rand()`, `norm_rand()`, `exp_rand()`, or `R_unif_index()` the random seed state is set accordingly.
142
127
cpp11 does _not_ do this, so you must include the calls to `GetRNGstate()` and `PutRNGstate()` _yourself_ if you use any of those functions in your C++ code.
143
128
See [R-exts 6.3 - Random number generation](https://cran.r-project.org/doc/manuals/r-release/R-exts.html#Random-numbers) for details on these functions.
144
129
@@ -162,31 +147,36 @@ void foo() {
162
147
}
163
148
```
164
149
165
-
## Mechanics of converting a package from Rcpp
166
-
167
-
1. Add cpp11 to `LinkingTo`
168
-
1. Convert all instances of `// [[Rcpp::export]]` to `[[cpp11::register]]`
169
-
1. Clean and recompile the package, e.g. `pkgbuild::clean_dll()` `pkgload::load_all()`
170
-
1. Run tests `devtools::test()`
171
-
1. Start converting function by function
172
-
- Remember you can usually inter-convert between cpp11 and Rcpp classes by going through `SEXP` if needed.
173
-
- Converting the code a bit at a time (and regularly running your tests) is the best way to do the conversion correctly and make progress
174
-
- Doing a separate commit after converting each file (or possibly each function) can make finding any regressions with [git bisect](https://youtu.be/KKeucpfAuuA) much easier in the future.
175
150
176
151
## Common issues when converting
177
152
178
153
### STL includes
179
154
180
155
Rcpp.h includes a number of STL headers automatically, notably `<string>` and `<vector>`, however the cpp11 headers generally do not. If you have errors like
181
156
182
-
> error: no type named 'string' in namespace 'std'
157
+
```
158
+
error: no type named 'string' in namespace 'std'
159
+
```
183
160
184
161
You will need to include the appropriate STL header, in this case `<string>`.
185
162
163
+
### Strict headers
164
+
165
+
If you see something like this:
166
+
167
+
```
168
+
In file included from file.cpp:1:
169
+
In file included from path/cpp11/include/cpp11.hpp:3:
Make sure to remove `PKG_CPPFLAGS=-DSTRICT_R_HEADERS` from `src/Makevars`.
175
+
186
176
### R API includes
187
177
188
178
cpp11 conflicts with macros declared by some R headers unless the macros `R_NO_REMAP` and `STRICT_R_HEADERS` are defined.
189
-
If you include `cpp11/R.hpp` before any R headers these macros will be defined appropriately, otherwise you may see errors like
179
+
If you include `cpp11.hpp` (or, at a minimum, `cpp11/R.hpp`) before any R headers these macros will be defined appropriately, otherwise you may see errors like
190
180
191
181
> R headers were included before cpp11 headers and at least one of R_NO_REMAP or STRICT_R_HEADERS was not defined.
192
182
@@ -197,12 +187,6 @@ Note that transitive includes of R headers (for example, those included by `Rcpp
197
187
198
188
If you use typedefs for cpp11 types or define custom types you will need to define them in a `pkgname_types.hpp` file so that `cpp_register()` can include it in the generated code.
199
189
200
-
### `cpp11::stop()` and `cpp11::warning()` with `std::string`
201
-
202
-
`cpp11::stop()` and `cpp11::warning()` are thin wrappers around `Rf_stop()` and `Rf_warning()`.
203
-
These are simple C functions with a `printf()` API, so do not understand C++ objects like `std::string`.
204
-
Therefore you need to call `obj.c_str()` when passing character data to them.
205
-
206
190
### Logical vector construction
207
191
208
192
If you are constructing a length 1 logical vector you may need to explicitly use a `r_bool()` object in the initializer list rather than `TRUE`, `FALSE` or `NA_INTEGER`.
0 commit comments