Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions man/cpp11-package.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

248 changes: 248 additions & 0 deletions vignettes/cpp11_faq.Rmd
Original file line number Diff line number Diff line change
@@ -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 <cpp11.hpp>

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 <cpp11.hpp>

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 <cpp11.hpp>

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<int>(my_env["foo"]) == 5);

return (fofo);
}
```

```{cpp11}
#include <cpp11.hpp>

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 <cpp11.hpp>

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 <cpp11.hpp>

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 <cpp11.hpp>

using namespace cpp11;
[[cpp11::register]]
cpp11::writable::logicals fn2() {
return {FALSE};
}
```

* Otherwise this will fail to compile:

```{cpp11, eval = FALSE}
#include <cpp11.hpp>

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.hpp>
[[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 <cpp11.hpp>
#include <string>

using namespace std;

[[cpp11::register]]
string foobar() {
return string("foo") + "-bar";
}
```


But this will compile and work as expected
```{cpp11}
#include <cpp11.hpp>
#include <string>

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.