繁体   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