如何使用可能为 NULL 的 Rcpp 字符串变量?

How to work with Rcpp strings variables which could be NULL?

我正在编写一个 R 包 + Rcpp 代码来与现有的 C++ 库一起工作。

在阅读了此处的教程后:https://gallery.rcpp.org/articles/optional-null-function-arguments/,我正在为如何使用 NULL 和字符串而苦苦挣扎。我很困惑,我无法从类型 Rcpp::Nullable<std::string> 转换为 std::string (或等效地 Rcpp::Nullable<Rcpp::String> 转换为 Rcpp::String

在 C++ 中,我正在检查字符串(在 C++ 中)是否为空。如果字符串为空,我想return NULL。如果字符串(在 C++ 中)不为空,我想 return 字符串。

我的示例代码如下,为简单起见,修改了Rcpp.package.skeleton()提供的函数rcpp_hello_world()。我的目标是在 R 中 return 包含字符串或 NULL(如果字符串为空)的列表 (Rcpp::List)。

#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 ;
}

上面示例中的结果变量 result_string 应该是 NULL"mystring"---但是,上面的总是 return NULL ,这不是所需的行为。

然后我尝试查看是否可以在 Rcpp::Nullable<std::string>std::string 之间转换类型:

std::string mystring = "helloworld";  
Rcpp::Nullable<std::string> result_string = R_NilValue;
std::string result_string(mystring);

这会导致编译错误:

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>>>')

我是否为此操作使用了错误的数据结构?或者如果值可能为 NULL,是否有更好的方法来处理字符串?

这是一个最基本的完整答案。在函数体中,您可以根据需要调整测试,这只是一个占位符示例。

代码

#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/Whosebug/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"

> 

德克在上面是正确的:从根本上说,我的误解与对 Rcpp::Nullable 的混淆有关。

the helper class Nullable<> is only used for the function signature

以下最终对我有用:

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::List z = Rcpp::List::create(Rcpp::Named("myresult") = nullptr);

    if (mystring.empty()) {
        z["myresult"] = R_NilValue;
    } else  {
        z["myresult"] = mystring;
    }
 
    return z ;
}