10

Rcpp用来包装一个用类 C ++ 编写的算法(不是我写的)(据我所知,没有 STL,没有提升,没有任何东西)。你可以在这里看到实现的算法(我正在包装kmeans_w_03)。因此,我numeric从 R 传入一个向量,然后需要将其转换为double数组。

目前我正在逐个元素地循环并从另一个元素中填充一个元素,如下所示:

SEXP testfn(SEXP weightvec, SEXP cluster_num_k){
    Rcpp::NumericVector weightR(weightvec) ;
    int point_num = weightR.size();
    double weight[point_num] ;
    for(int i = 0; i < point_num; ++i) {
      weight[i] = weightR[i];
    }
}

但是对于单元素数值向量,我可以利用 Rcpp 的漂亮as转换功能:

int cluster_num = Rcpp::as<int>(cluster_num_k);

但是,对长度 > 1 的数值向量尝试类似的操作会导致崩溃或错误,具体取决于语法的确切变体:

double weight[point_num] = Rcpp::as<double>(weightvec);

我不一定介意循环,但我完全是新手,我怀疑有更好的方法。我已经阅读了 Rcpp-introduction、hadley 的 wiki 教程和 RcppExamples,但还没有找到任何可以解决这个问题的东西,但这并不意味着我没有错过它。我对 Doxygen Rcpp 文档的阅读是as可以转换为 STL 向量但不能转换为数组(但我很难阅读这些文档,所以我怀疑我错了)。如果是这样,我想我可以转换为向量,然后转换为数组....

所以我的问题是:有没有更好的(更少的代码行,更具表现力的代码,甚至可能是能够避免内存分配)的方式来将 a 转换NumericVector为 a double[]

4

3 回答 3

8

阿里,在前面的回答中,约翰提出了一个很好的观点。稍微扩展一下,这里有几个问题

  • 您正在处理一个具有过时编码标准的库,它需要一个double[]*double
  • 您想使用更好的编码标准并利用Rcpp

好吧,不要害怕,我们有一个简单的解决方案。像往常一样实例化Rcpp::NumericVector X(weightvec);,然后将其传递给您的函数foo()(或其他)

foo(X.begin())

它为您提供 required double*,如果需要,X.size()提供长度。因为你来自 R,所以当你之后返回 R 时,你不需要担心范围和生命周期。

如果您需要更明确,我还使用了 uglier &(X[0])

此外,Rcpp::as<>()施法者也可以工作std::vector<double>,所以你可以做

std::vector<double> x = Rcpp::as<std::vector<double> >(weightvec);

但除了转换为 C++ 类型之外,它在这里一无所获。

最后,如果 Josh 或其他 C 顽固分子在附近,所有这一切都利用了这样一个事实,即SEXP来自 R 的 you 保证具有连续的 C 指针,因此您也可以通过非常古老的学校REAL(weightvec)

于 2012-12-24T14:40:28.430 回答
4

编写一个不使用标准库(您所说的“STL”)的 C++ 程序并不是我认为的“常规 C++”。标准库是标准定义的语言的一部分。因此,使用标准中定义的工具并不是非常规的 C++。恰恰相反,我认为故意忽略这些设施本身就是非常规的。它使用 C++ 作为“更好的 C”,或“带有类的 C”。这没有抓住重点。

牢记这一点,当查看您的循环打算完成的任务时,我的第一个倾向是使用transform将源复制到目标,并将 avector作为目标。

你也有一个中介在这里工作——你首先(似乎)复制weightVec到一个新构建NumericVector的 ,然后复制其中的元素——但是NumericVector被扔掉了。这对我来说似乎很浪费。

这是编写此代码时我会想到的基本模式:

vector<double> weight;
transform( weightVec.begin(), weightVec.end(), back_inserter(weight), converter() );
return weight;

这里缺少一些语法位,如果不了解更多有关正在使用的组件,我无法填写。但考虑到你在做什么,哲学似乎是合理的。

例如,SEXP对象可能没有begin()end()方法。但是,您已经直接NumericVectorSEXP对象构造 a,因此它SEXP可能具有模拟设施begin()end()您可以采用甚至可能直接使用。

我在上面使用的converter()构造是函数、仿函数或 lambda(在 C++11 中)的占位符,它将单个SEXP元素转换为double. 同样,我不知道实现此操作所需的详细信息,但它必须是可能的,因为您已经以另一种方式执行此操作。

于 2012-12-24T14:15:32.767 回答
1

如果您的问题是如何将数据从 C++ 数组复制Rcpp::NumericVector到 C++ 数组,transform()这是一个很好的答案。但是,如果您想从中获取内部数组Rcpp::NumericVector,其中不包括任何复制,您可以执行与从中提取数组完全相同的操作std::vector

double* arr = &vec[0];

其中 vec 是一个Rcpp::NumericVector

于 2017-01-10T15:21:07.503 回答