[英]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.