我正在使用Rcpp
来包装一个在C语言C ++中编写的算法(不是我)(没有STL,没有提升,没有任何东西,据我所知)。你可以看到实现的算法here(我正在包装kmeans_w_03
)。因此,我从R传入numeric
向量,然后需要将其转换为double
数组。
目前我正在循环逐个元素并从“tother”中填充一个,就像这样:
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);
尝试类似长度的东西&gt;但是,1个数字向量会导致崩溃或错误,具体取决于语法的确切变体:
double weight[point_num] = Rcpp::as<double>(weightvec);
我不一定介意循环,但我是一个完全新手,并怀疑有更好的方法。我已经阅读了Rcpp介绍,hadley的wiki教程和RcppExamples,但还没有找到解决这个问题的任何内容,但这并不意味着我不会错过它。我读到的Doxygen Rcpp文档是as
可以转换为STL向量而不是数组(但我很难读取这些文档,所以我怀疑我错了)。如果是这样,我想我可以投射到一个矢量,然后再投射到数组......
所以我的问题是:是否有更好的(更少的代码行,更具表现力的代码,甚至可以避免内存分配)方式将NumericVector
转换为{{1 }}?
答案 0 :(得分:8)
Ari,在之前的回答中,John提出了一个很好的观点。为了扩展一点,这里有一些问题
double[]
或*double
好吧,不要害怕,我们有一个简单的解决方案。像往常一样立即对齐Rcpp::NumericVector X(weightvec);
,然后将其传递给您的函数foo()
(或其他)
foo(X.begin())
为您提供所需的double*
,如果需要X.size()
则提供长度。因为你来自R,所以当你之后返回R时,你不需要担心范围和生命周期。
如果你需要更明确,我也使用了丑陋的&(X[0])
。
此外,Rcpp::as<>()
施法者也适用于std::vector<double>
,所以你可以做到
std::vector<double> x = Rcpp::as<std::vector<double> >(weightvec);
但除了转换为C ++类型之外,它在这里没有任何收获。
最后,如果Josh或其他C顽固分子在附近,所有这些都使用了这样一个事实:来自R的SEXP
保证有连续的C指针,所以你也可以通过这个非常古老的学校{ {1}}。
答案 1 :(得分:4)
编写一个不使用标准库(你称之为“STL”)的C ++程序并不是我认为的“常规C ++”。标准库是 标准所定义语言的一部分。因此,使用标准中定义的工具不是非常规的C ++。恰恰相反,我建议故意忽视这些设施本身就是非传统的。它使用C ++作为“更好的C”,或者“C with classes”。而那就错过了重点。
考虑到这一点,在查看您的循环打算完成的内容时,我的第一个倾向是使用transform
将源复制到目标,并将vector
作为目标。
您还有一位中间人在这里工作 - 您首先(似乎)将weightVec
复制到新构建的NumericVector
,然后复制其中的元素 - 但{{{ 1}}被扔掉了。这对我来说似乎很浪费。
以下是编写此代码时我想到的基本模式:
NumericVector
这里缺少一些语法位,如果不了解更多关于组件的内容,我无法填写。但鉴于你正在做的事情,哲学似乎是合理的。
例如,vector<double> weight;
transform( weightVec.begin(), weightVec.end(), back_inserter(weight), converter() );
return weight;
对象可能没有SEXP
或begin()
方法。但是,您已经直接从end()
对象构建NumericVector
,因此SEXP
可能具有SEXP
和begin()
的模拟工具,您可以采用或可能甚至直接使用。
我上面使用的end()
构造是函数,函子或lambda(在C ++ 11中)的占位符,它将单个converter()
元素转换为SEXP
。我再次不知道为了实现这一点我需要的细节,但它必须是可能的,因为你已经以另一种方式做到了这一点。
答案 2 :(得分:1)
如果您的问题是如何将数据从Rcpp::NumericVector
复制到C ++数组,那么transform()
就是一个很好的答案。但是如果你想从Rcpp::NumericVector
获取内部数组(不包括任何复制),你可以使用std::vector
中的提取数组完全相同:
double* arr = &vec[0];
其中vec是Rcpp::NumericVector
。