簡體   English   中英

為 std::array 專門化 Rcpp::as()

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM