diff --git a/man/cpp11-package.Rd b/man/cpp11-package.Rd index d7931614..4a4f147d 100644 --- a/man/cpp11-package.Rd +++ b/man/cpp11-package.Rd @@ -15,6 +15,7 @@ Provides a header only, C++11 interface to R's C \seealso{ Useful links: \itemize{ + \item \url{https://cpp11.r-lib.org} \item \url{https://github.com/r-lib/cpp11} \item Report bugs at \url{https://github.com/r-lib/cpp11/issues} } diff --git a/vignettes/cpp11_faq.Rmd b/vignettes/cpp11_faq.Rmd new file mode 100644 index 00000000..088de12b --- /dev/null +++ b/vignettes/cpp11_faq.Rmd @@ -0,0 +1,248 @@ +--- +title: "cpp11 FAQ" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{cpp11 FAQ} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +```{r, include = FALSE} +knitr::opts_chunk$set( + collapse = TRUE, + comment = "#>" +) +library(cpp11) +``` + +Intended to answer common questions about the usage of cpp11 objects + +## FAQ + +#### 1. How do I add elements to a named list? + + * Use push_back() with named literals to add elements to a named list + +```{cpp11} +#include + +using namespace cpp11; + + +[[cpp11::register]] +cpp11::list foo_push() { + cpp11::writable::list x; + x.push_back({"foo"_nm = 1}); + return x; +} +``` + +#### 2. How do I create a new empty environment? + + * Use the C++ `auto` keyword with R's `new.env` to return a new empty environment. This should then be passed to `cpp11::environment` before use + +```{cpp11} +#include + +using namespace cpp11; + +[[cpp11::register]] +cpp11::environment get_environment() { + auto new_env = cpp11::package("base")["new.env"]; + cpp11::environment my_env(new_env()); + return my_env; +} + +``` + +#### 3. How do I assign and retrieve values in an environment? What happens if I try to get a value that doesn't exist? + + * To assign and retrieve values in an environment use brackets to access values in your environment by name. + * To check if a named value exists use `my_env["bar"] == R_UnboundValue` which returns `TRUE` if the value is unassigned and NULL. + +```{cpp11} +#include + +using namespace cpp11; +[[cpp11::register]] +cpp11::r_bool foo_exists(){ + auto new_env = cpp11::package("base")["new.env"]; + cpp11::environment my_env(new_env()); + + my_env["foo"] = 5; + cpp11::r_bool fofo = (as_cpp(my_env["foo"]) == 5); + + return (fofo); +} +``` + +```{cpp11} +#include + +using namespace cpp11; + +[[cpp11::register]] +cpp11::r_bool bar_exists(){ + auto new_env = cpp11::package("base")["new.env"]; + cpp11::environment my_env(new_env()); + + + cpp11::r_bool barbar = (my_env["bar"] == R_UnboundValue); + + return (!barbar); +} +``` + +#### 4. How can I create a `cpp11:raws` from a `std::string`? + + * Push back the contents individually + +```{cpp11} +#include + +using namespace cpp11; +[[cpp11::register]] +cpp11::raws push() { + + std::string x("hi"); + cpp11::writable::raws out; + + for (auto c : x) { + out.push_back(c); + } + + return out; + } +``` + +#### 5. What are the underlying types of cpp11 objects? + + | vector | element + | --- | --- + | integers | int + | doubles | double + | logical | r_bool + | strings | r_string + | raws | uint8_t + | list | SEXP + +#### 6. How do I create a new empty list? + +`cpp11::writable::list x;` + +#### 7. How do I retrieve (named) elements from a named vector/list? + +`x["foo"]` + +#### 8. How can I tell whether a vector is named? + + * Use the `named()` method for vector classes + +```{cpp11} +#include + +using namespace cpp11; +[[cpp11::register]] +cpp11::r_bool is_named() { + cpp11::writable::list s; + s.push_back({writable::integers ({1})}); + return(s.named()); + } +``` + +#### 9. What are the types for C++ iterators? + + * Iterators are internal classes. An example of an iterator for + doubles would be `cpp11::doubles::iterator` + +#### 10. How do I return cpp11::writable::logicals() objects? + + * Use brace initialization: + +```{cpp11} +#include + +using namespace cpp11; +[[cpp11::register]] +cpp11::writable::logicals fn2() { + return {FALSE}; +} +``` + + * Otherwise this will fail to compile: + +```{cpp11, eval = FALSE} +#include + +using namespace cpp11; +[[cpp11::register]] +cpp11::writable::logicals fn() { + return FALSE; +} +``` + + * This happens because the first case uses the R_xlen_t size constructor and the second uses the std::initializer_list<>() constructor. + +#### 11. Does cpp11 support default arguments? + + * cpp11 does not support default arguments. Instead cpp11 registered functions can be wrapped in an R function for default argument support + +```{cpp11} +#include +[[cpp11::register]] +std::string dims(bool length) { + if(length) { + return ("length"); + } + return ("width"); +} +``` + +```{r} +full_dims <- function(length = FALSE) { + dims(length) +} +full_dims(TRUE) +#> "length" +full_dims() +#> "width" +``` + +#### 12. Why do I have to include `using namespace` in my code as well as `std::` inside of `[[cpp11::register]]` functions? + + + * Since namespace definitions will not be in the registration file generated by cpp11, types used in function definitions that are decorated with `[[cpp11::register]]` need to be fully qualified. However type names within those functions will work as expected. + +The following won't compile +```{cpp11, eval = FALSE} +#include +#include + +using namespace std; + +[[cpp11::register]] +string foobar() { + return string("foo") + "-bar"; +} +``` + + +But this will compile and work as expected +```{cpp11} +#include +#include + +using namespace std; +[[cpp11::register]] +std::string foobar() { + return string("foo") + "-bar"; +} +``` + +#### 13. How do I modify a vector in place? + + * Using `writable::` will always make a copy, but it has a move constructor, so you can use `cpp11::writable::integers(std::move(x))` and it won't make a copy of the data. + + + +