返回给定 SEXP 的子集,而无需知道实际的内部数据类型

Return subset of a given SEXP without knowing the actual internal data type

本文关键字:数据类型 内部 SEXP 子集 返回      更新时间:2023-10-16

我正在编写一个 R 包来提供调试帮助程序函数,以便gdb打印 R s SEXPRcpp s 数据类型的变量值。

C/C++ 是一种强类型语言,但我想避免查询SEXP的内部数据类型,并使用一堆 if 进行硬编码调度。

我如何通过这样的函数签名使用索引范围实现通用子集函数:

SEXP dbg_subset(SEXP x, R_xlen_t index_from, R_xlen_t index_to);

一种可能的解决方案是为每个可能的签名编写上述函数,例如。 对于INTSXPLGLSXPSTRSXP...但我很懒;-(

注意:我不能使用C++模板,因为链接器只会为我的C++代码中使用的数据类型创建模板实例(与"调试中的库"不同(和gdb 没有编译器可以在输入C++表达式以查询变量时"动态"创建缺少的模板实例。

编辑:看到这个答案(但它是基于我想避免的模板(:

可以将C++模板与RCPP_RETURN_VECTOR宏一起使用。此宏将确保为 all(?( 实例化模板R 数据类型:

#include <Rcpp.h>
// [[Rcpp::plugins(cpp11)]]
template <int RTYPE>
Rcpp::Vector<RTYPE> debug_subset_impl(Rcpp::Vector<RTYPE> x,
                                      R_xlen_t index_from,
                                      R_xlen_t index_to){
    // range [index_from, index_to)
    Rcpp::Vector<RTYPE> subset(index_to - index_from);
    std::copy(x.cbegin() + index_from, x.cbegin() + index_to, subset.begin());
    // special case for factors == INTSXP with "class" and "levels" attribute
    if (x.hasAttribute("levels")){
        subset.attr("class") = x.attr("class");
        subset.attr("levels") = x.attr("levels");
    }
    return subset;
}

// [[Rcpp::export]]
SEXP dbg_subset(SEXP x, R_xlen_t index_from, R_xlen_t index_to){
    // 1-based -> 0-based
    RCPP_RETURN_VECTOR(debug_subset_impl, x, index_from - 1, index_to - 1);
}
/*** R
set.seed(42)
dbg_subset(1:100, 3, 6)
dbg_subset(runif(100), 3, 6)
dbg_subset(letters, 3, 6)
dbg_subset(as.factor(letters), 3, 6)
*/

输出:

> Rcpp::sourceCpp('58965423.cpp')
> set.seed(42)
> dbg_subset(1:100, 3, 6)
[1] 3 4 5
> dbg_subset(runif(100), 3, 6)
[1] 0.2861395 0.8304476 0.6417455
> dbg_subset(letters, 3, 6)
[1] "c" "d" "e"
> dbg_subset(as.factor(letters), 3, 6)
[1] c d e
Levels: a b c d e f g h i j k l m n o p q r s t u v w x y z