[英]Specialising Rcpp::as() for std::array
我的一个项目将 C++11 std::array
用于固定大小的数组类型,因此我试图专门Rcpp::as()
以方便从SEXP
到这些类型的转换。 由于这需要部分专业化,因此我遵循了 Rcpp-extending 中概述的Exporter
路线:
#include <RcppCommon.h>
#include <array>
namespace Rcpp {
namespace traits {
// Partial specialisation to allow as<array<T,D>>(...)
template <typename ElementType, int Dimensionality>
class Exporter<std::array<ElementType,Dimensionality>>
{
private:
std::array<ElementType,Dimensionality> value;
public:
Exporter (SEXP x)
{
std::vector<ElementType> vec = as<std::vector<ElementType>>(x);
if (vec.size() != Dimensionality)
throw Rcpp::exception("Array does not have the expected number of elements");
for (int i=0; i<Dimensionality; i++)
value[i] = vec[i];
}
std::array<ElementType,Dimensionality> get () { return value; }
};
} // traits namespace
} // Rcppnamespace
#include <Rcpp.h>
然后包中的其他代码可以执行,例如,
std::array<double,3> arr = Rcpp::as<std::array<double,3>>(vec);
出于示例目的,我将其捆绑到一个最小的包中; “真正的”应用程序在这里。
问题是这种方法在本地(macOS,clang)编译并适合我,但 gcc 不喜欢它。 最小包上的 GitHub CI 操作的输出如下。
* installing *source* package ‘Rcpp.asArray’ ...
** using staged installation
** libs
g++ -std=gnu++11 -I"/opt/R/4.2.2/lib/R/include" -DNDEBUG -I'/home/runner/work/_temp/Library/Rcpp/include' -I/usr/local/include -fpic -g -O2 -c main.cpp -o main.o
In file included from /home/runner/work/_temp/Library/Rcpp/include/Rcpp/as.h:25,
from /home/runner/work/_temp/Library/Rcpp/include/RcppCommon.h:169,
from array.h:4,
from main.cpp:1:
/home/runner/work/_temp/Library/Rcpp/include/Rcpp/internal/Exporter.h: In instantiation of ‘Rcpp::traits::Exporter<T>::Exporter(SEXP) [with T = std::array<double, 3>; SEXP = SEXPREC*]’:
/home/runner/work/_temp/Library/Rcpp/include/Rcpp/as.h:87:41: required from ‘T Rcpp::internal::as(SEXP, Rcpp::traits::r_type_generic_tag) [with T = std::array<double, 3>; SEXP = SEXPREC*]’
/home/runner/work/_temp/Library/Rcpp/include/Rcpp/as.h:152:31: required from ‘T Rcpp::as(SEXP) [with T = std::array<double, 3>; SEXP = SEXPREC*]’
main.cpp:8:62: required from here
/home/runner/work/_temp/Library/Rcpp/include/Rcpp/internal/Exporter.h:31:42: error: no matching function for call to ‘std::array<double, 3>::array(SEXPREC*&)’
31 | Exporter( SEXP x ) : t(x){}
| ^~~~
In file included from /usr/include/c++/11/tuple:39,
from /usr/include/c++/11/bits/hashtable_policy.h:34,
from /usr/include/c++/11/bits/hashtable.h:35,
from /usr/include/c++/11/unordered_map:46,
from /home/runner/work/_temp/Library/Rcpp/include/Rcpp/platform/compiler.h:153,
from /home/runner/work/_temp/Library/Rcpp/include/Rcpp/r/headers.h:62,
from /home/runner/work/_temp/Library/Rcpp/include/RcppCommon.h:30,
from array.h:4,
from main.cpp:1:
/usr/include/c++/11/array:95:12: note: candidate: ‘std::array<double, 3>::array()’
95 | struct array
| ^~~~~
/usr/include/c++/11/array:95:12: note: candidate expects 0 arguments, 1 provided
/usr/include/c++/11/array:95:12: note: candidate: ‘constexpr std::array<double, 3>::array(const std::array<double, 3>&)’
/usr/include/c++/11/array:95:12: note: no known conversion for argument 1 from ‘SEXP’ {aka ‘SEXPREC*’} to ‘const std::array<double, 3>&’
/usr/include/c++/11/array:95:12: note: candidate: ‘constexpr std::array<double, 3>::array(std::array<double, 3>&&)’
/usr/include/c++/11/array:95:12: note: no known conversion for argument 1 from ‘SEXP’ {aka ‘SEXPREC*’} to ‘std::array<double, 3>&&’
make: *** [/opt/R/4.2.2/lib/R/etc/Makeconf:178: main.o] Error 1
ERROR: compilation failed for package ‘Rcpp.asArray’
* removing ‘/home/runner/work/Rcpp.asArray/Rcpp.asArray/Rcpp.asArray.Rcheck/Rcpp.asArray’
我不太了解Rcpp
的内部结构,无法确定,但看起来Exporter
的默认实现优先于自定义实现,并且失败是因为SEXP
没有std::array
构造函数,这将涉及侵入性修改。
任何人都可以提出解决此问题的方法吗?
据我所知,您的方法遗漏了一些内容。 最好的指南仍然是 Rcpp Gallery 中@coatless 的可信示例
之后,我将您的标题(稍微重命名 - 抱歉,个人风格悄悄进入)减少到(跳过第 1 步中的声明)到
namespace Rcpp {
namespace traits {
template <typename T, std::size_t D> class Exporter<std::array<T,D>> {
typedef typename std::array<T,D> ATD;
// Convert the type to a valid rtype.
const static int RTYPE = Rcpp::traits::r_sexptype_traits<T>::rtype;
Rcpp::Vector<RTYPE> vec;
public:
Exporter(SEXP x): vec(x) {
if (TYPEOF(x) != RTYPE) Rcpp::stop("Wrong R type for array");
}
ATD get() {
ATD x;
if (vec.size() != D) Rcpp::stop("Array does not have the exp nb of elements");
std::memcpy(x.begin(), vec.begin(), D*sizeof(T));
return x;
}
};
}
}
我将您的使用示例更改/简化为使用 Rcpp Attribute,因为,嘿,它是 2022 年,我们已经使用它们近十年了,所以.Call()
不再是必需的:
// [[Rcpp::export]]
void foo() {
Rcpp::NumericVector v = Rcpp::NumericVector::create(1,2,3);
Rcpp::print(v);
std::array<double,3> a = Rcpp::as<std::array<double,3>>(v);
Rcpp::Rcout << "Hi "
<< a[0] << " "
<< a[1] << " "
<< a[2] << std::endl;
}
然后按预期工作(这里是从 shell 中加载你的包的littler
:
edd@rob:~/git/rcppasarray(main)$ r -lRcpp.asArray -e'Rcpp.asArray:::foo()'
[1] 1 2 3
Hi 1 2 3
edd@rob:~/git/rcppasarray(main)$
它可能需要一个显式的调整大小步骤——我没有太多地使用std::array
来确定。 我会再清理一下并向您发送 PR。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.