为 Rcpp 打印泛型 class

print generic for Rcpp class

我在为 Rcpp class 编写 R 通用打印机时遇到一些问题。想想 http://dirk.eddelbuettel.com/code/rcpp/Rcpp-modules.pdf 第 8 页的 Uniform 示例。我试过像这样定义一个泛型:

# Create new Uniform object:
uniform = Uniform$new(1, 2)
class(uniform)

## [1] "Rcpp_Uniform"
## attr(,"package")
## [1] "uniform"


# Printer for the object:
print.Rcpp_Uniform = function (x, ...) { message("Hi, I am an uniform object") }

现在,如果我只输入 uniform,我会得到:

C++ object <000000000d825c80> of class 'Uniform' <000000000287b090>

但这是我尽量避免的。直接调用打印机给出了我喜欢的东西:

print(uniform)
## Hi, I am an uniform object

有没有办法不调用打印函数直接使用自定义打印机?

感谢 Dirks 的提示,我有了一个解决方案。这是包含统一 class(Dirks Rcpp Modules 文档的副本)和 Rcpp 模块定义的 cpp 文件 uniform.cpp

// BEGIN uniform.cpp

#include <Rcpp.h>

using namespace Rcpp;

class Uniform {
public:
  Uniform(double min_, double max_) : min(min_), max(max_) {}
  NumericVector draw(int n) const {
    RNGScope scope;
    return runif( n, min, max );
  }
  double min, max;
};
double uniformRange( Uniform* w) {
  return w->max - w->min;
}
RCPP_MODULE(unif_module) {
  class_<Uniform>( "Uniform" )
  .constructor<double,double>()
  .field( "min", &Uniform::min )
  .field( "max", &Uniform::max )
  .method( "draw", &Uniform::draw )
  .method( "range", &uniformRange )
  ;
}

// END uniform.cpp

现在可以获取和使用:

library(Rcpp)
## Warning: package 'Rcpp' was built under R version 3.4.3

sourceCpp(file = "uniform.cpp")

uniform = Uniform$new(0, 10)

# Default printer:
uniform
## C++ object <00000000137a2e90> of class 'Uniform' <0000000015256dc0>

class(uniform)
## [1] "Rcpp_Uniform"
## attr(,"package")
## [1] ".GlobalEnv"

现在的线索是将方法 show 定义为 S4 class Rcpp_Uniform 的自定义打印机。之后打印机执行所需的操作:

setMethod("show", class(uniform), function (object) {
  cat("\n Hi, I am an uniform object!\n")
  cat("\n I was initialized with a minimum value of", object$min)
  cat("\n and a maximum value of ", object$max, ".\n", sep = "")
  cat("\n Therefore my range is ", object$range(), ".", sep = "")
  cat("\n\n")
})
## [1] "show"

uniform
## 
##  Hi, I am an uniform object!
## 
##  I was initialized with a minimum value of 0
##  and a maximum value of 10.
## 
##  Therefore my range is 10.

在包中使用

要在将 C++ class 公开到 R 之后将该打印机设置为默认打印机,只需创建一个 R 文件(例如 R/uniform_printer.R) 并将以下代码放在那里:

setMethod("show", "Rcpp_Uniform", function (object) {
  cat("\n Hi, I am an uniform object!\n")
  cat("\n I was initialized with a minimum value of", object$min)
  cat("\n and a maximum value of ", object$max, ".\n", sep = "")
  cat("\n Therefore my range is ", object$range(), ".", sep = "")
  cat("\n\n")
})

请注意,有必要通过字符串明确引用 class(此处为 Rcpp_Uniform)。

这里的一个缺点是,这会在构建包时发出警告,因为在构建包时没有 class 的定义。如果在获取 cpp 文件之前从上方运行 setMethod 函数,则会出现相同的警告。

避免此警告的方法是在 setMethod 前面设置一个 class。这看起来像这样:

setClass("Rcpp_Uniform")
setMethod("show", "Rcpp_Uniform", function (object) {
  cat("\n Hi, I am an uniform object!\n")
  cat("\n I was initialized with a minimum value of", object$min)
  cat("\n and a maximum value of ", object$max, ".\n", sep = "")
  cat("\n Therefore my range is ", object$range(), ".", sep = "")
  cat("\n\n")
})

老实说,我不知道这有多合适。但它在一个包中工作正常。