【问题标题】:Mixing Rcpp modules and Rcpp::export混合 Rcpp 模块和 Rcpp::export
【发布时间】:2020-06-06 07:12:24
【问题描述】:

我想公开一个 C++ 类和一个函数,该函数将该类的对象作为 R 的参数。我必须遵循简化的示例。我使用

创建了一个包
Rscript -e 'Rcpp::Rcpp.package.skeleton("soq")'

并将以下代码放入soq_types.h

#include <RcppCommon.h>
#include <string>

class Echo {
  private:
  std::string message;
  public:
  Echo(std::string message) : message(message) {}
  Echo(SEXP);

  std::string get() { return message; }
};

#include <Rcpp.h>

using namespace Rcpp;

RCPP_MODULE(echo_module) {
  class_<Echo>("Echo")
  .constructor<std::string>()
  .method("get", &Echo::get)
  ;
};

//// [[Rcpp::export]]
void shout(Echo e) {
  Rcout << e.get() << "!" << std::endl;
}

请注意,最后一条注释有多余的斜线,不会导致函数被导出。当我现在运行时:

$> Rscript -e 'Rcpp::compileAttributes()'
$> R CMD INSTALL .

R> library(Rcpp)
R> suppressMessages(library(inline))
R> library(soq)
R> echo_module <- Module("echo_module", getDynLib("soq"))
R> Echo <- echo_module$Echo
R> e <- new(Echo, "Hello World")
R> print(e$get())

一切都很好。不幸的是,如果我启用Rcpp::export,请执行compileAttributes() 并重新安装,我得到:

** testing if installed package can be loaded from temporary location
Error: package or namespace load failed for ‘soq’ in dyn.load(file, DLLpath = DLLpath, ...):
 unable to load shared object '/home/brj/R/x86_64-pc-linux-gnu-library/3.6/00LOCK-soq/00new/soq/libs/soq.so':
  /home/brj/R/x86_64-pc-linux-gnu-library/3.6/00LOCK-soq/00new/soq/libs/soq.so: undefined symbol: _ZN4EchoC1EP7SEXPREC
Error: loading failed
Execution halted
ERROR: loading failed

我的问题是:如何让两者都工作?

我在 R.3.6.3 和

R> sessionInfo()
....
other attached packages:
[1] inline_0.3.15 Rcpp_1.0.4.6 
....

附录

对于那些试图遵循上述示例的人:源文件的确切名称是 &lt;package_name&gt;_types.h 非常重要。否则,自动生成的RcppExports.cpp 不会#include 它,因此Echo 类不会在那里定义。这会导致编译错误。

【问题讨论】:

  • 想了想最好的例子,我有点挠头,但失败了。我认为我们在 somewhere 这样做,但现在我无法指出在哪里 :-/ 首先,尝试使用两个文件将 Rcpp Modules 业务与 compileAttributes 业务分开。使用inst/include/packagename_types.h 是否需要联合标头。
  • 这不是你的问题,但我也有点想知道这将如何工作。我对模块的工作原理了解有限。但我的理解是你不能从 R 端传递一个 Echo 对象。您可以从 R 端向它传递一个 S4 对象(在 R 中称为 Echo 类),或者您可以向它传递一个指向您使用 e &lt;- new(Echo, "Hello World") 创建的 Echo 对象的指针,但我认为您不能传递一个Echo 对象本身。这是对的@DirkEddelbuettel,还是我离这里很远?就像我说的,Modules 不是 Rcpp 我不经常访问的角落之一。
  • 好点。 Rcpp 属性可能不知道Echo 的转换。早点出门的时候错过了。
  • 你为什么不让shout成为你的类的方法,并按照@duckmayr的建议使用new?然后你可以做类似e$shout()的事情。
  • @JosephWood 提供更多背景信息:在我的日常工作中,Echo 是一个 RNG,它重新实现了 Java 的 COLT 随机数生成的一部分。作为临时解决方案,我只是向 RNG 添加了另一种方法而不是传递它,但我不喜欢这个有两个原因:1)如果我想将两个类传递给一个函数怎么办? 2) 我现在添加到我的 RNG 类的方法不属于那里 (IMO)。

标签: c++ r rcpp


【解决方案1】:

错误消息是在抱怨声明但未定义的Echo(SEXP),这是为了扩展Rcpp::as&lt;&gt;。对于由 Rcpp 模块处理的类,使用 RCPP_EXPOSED_* 宏更容易:

 #include <Rcpp.h>

class Echo {
private:
    std::string message;
public:
    Echo(std::string message) : message(message) {}

    std::string get() { return message; }
};

RCPP_EXPOSED_AS(Echo);

using namespace Rcpp;

RCPP_MODULE(echo_module) {
    class_<Echo>("Echo")
    .constructor<std::string>()
    .method("get", &Echo::get)
    ;
};

// [[Rcpp::export]]
void shout(Echo e) {
    Rcout << e.get() << "!" << std::endl;
}

/***R
e <- new(Echo, "Hello World")
print(e$get())
shout(e)
*/ 

输出:

> Rcpp::sourceCpp('62228538.cpp')

> e <- new(Echo, "Hello World")

> print(e$get())
[1] "Hello World"

> shout(e)
Hello World!

所有这些都不是在一个包中,而是使用Rcpp::sourceCpp。不过,我希望它也能在一个包中工作。

【讨论】:

  • 谢谢,可以确认它也适用于我的测试包!
  • 现在我们可以在你们两个之间快速获得一份 Rcpp Gallery 文章以更清楚地记录这一点吗?
  • 我现在正在阅读现有示例,并将对其进行尝试。如果可以的话,我希望通过电子邮件发送一些东西。
猜你喜欢
  • 2023-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-07
  • 1970-01-01
  • 2021-02-25
相关资源
最近更新 更多