I am writing an R package + Rcpp code to work with an existing C++ library.
After going through the tutorials here: https://gallery.rcpp.org/articles/optional-null-function-arguments/ , I'm struggling with how to work with NULL and strings. I am confused that I cannot cast from type Rcpp::Nullable<std::string>
to std::string
(or equivalently Rcpp::Nullable<Rcpp::String>
to Rcpp::String
Within C++, I am checking for whether the string (in C++) is empty or not. If the string is empty, I want to return NULL. If the string (in C++) is not empty, I want to return the string.
My example code is below, modifying the function rcpp_hello_world()
provided by the Rcpp.package.skeleton()
for simplicity. My goal is to return within R a list (Rcpp::List) containing either a string, or NULL (if the string is empty).
#include <Rcpp.h>
#include <string>
using namespace Rcpp;
// [[Rcpp::export]]
Rcpp::List rcpp_hello_world() {
// After calculations from external C++ library,
// the variable 'mystring' will either empty (i.e. "") or populated (e.g. "helloworld")
std::string mystring = "helloworld"; // string non-empty
Rcpp::Nullable<std::string> result_string = R_NilValue;
if (!mystring.empty()) {
std::string result_string(mystring);
}
Rcpp::List z = List::create(result_string);
return z ;
}
The resulting variable result_string
in the above example should either be NULL
or "mystring"
---however, the above will always return NULL
, which is not the desired behavior.
I then tried to see if I could even convert types between Rcpp::Nullable<std::string>
and std::string
:
std::string mystring = "helloworld";
Rcpp::Nullable<std::string> result_string = R_NilValue;
std::string result_string(mystring);
This results in a compilation error:
error: redefinition of 'result_string' with a different type: 'std::string'
(aka 'basic_string<char, char_traits<char>, allocator<char>>') vs 'Rcpp::Nullable<std::string>'
(aka 'Nullable<basic_string<char, char_traits<char>, allocator<char>>>')
Am I using the wrong data structures for this operation? Or is there a better way to work with strings if the value could be NULL?
Here is a minimally complete answer. In the function body you can adjust your tests according to your needs, this is just a placeholder example.
#include <Rcpp.h>
// [[Rcpp::export]]
Rcpp::List foo(Rcpp::NumericVector v) {
// we just us a random vector here to determine: if positive
// we inject a string, if negative NULL
const std::string mystring = "helloworld"; // if positive
int n = v.size();
Rcpp::List z(n);
for (int i=0; i<n; i++) {
if (v[i] < 0) {
z[i] = mystring;
} else {
z[i] = R_NilValue;
}
}
return z;
}
/*** R
set.seed(123)
foo(rnorm(3)))
set.seed(123456)
foo(rnorm(3))
*/
> Rcpp::sourceCpp("~/git/stackoverflow/70601602/answer.cpp")
> set.seed(123)
> foo(rnorm(3))
[[1]]
[1] "helloworld"
[[2]]
[1] "helloworld"
[[3]]
NULL
> set.seed(123456)
> foo(rnorm(3))
[[1]]
NULL
[[2]]
[1] "helloworld"
[[3]]
[1] "helloworld"
>