使用 Rcpp 模块向 R 公开简单的 C++ Student 类

Posted

技术标签:

【中文标题】使用 Rcpp 模块向 R 公开简单的 C++ Student 类【英文标题】:Expose simple C++ Student class to R using Rcpp modules 【发布时间】:2018-12-06 20:52:14 【问题描述】:

我正在尝试使用包中的 Rcpp 将 C++ 中的一个简单 Student 类公开给 R。这是我的设置...

src/

Student.hpp
//  Student.hpp

#ifndef Student_hpp
#define Student_hpp

#include <string>
#include <vector>

class Student

public:

    // Constructor
    Student(std::string name, int age, bool male);

    // Getters
    std::string GetName();
    int GetAge();
    bool IsMale();
    std::vector<int> GetFavoriteNumbers();

    // Methods
    bool LikesBlue();

private:

    // Member variables
    std::string name;
    int age;
    bool male;
    std::vector<int> favoriteNumbers;
;

#endif /* Student_hpp */
学生.cpp
//  Student.cpp

#include "Student.hpp"

// Constructor
Student::Student(std::string name, int age, bool male) 
  this->name = name;
  this->age = age;
  this->male = male;
  this->favoriteNumbers = 2, 3, 5, 7, 11;


// Getters
bool Student::IsMale()  return male; 
int Student::GetAge()  return age; 
std::string Student::GetName()  return name; 
std::vector<int> Student::GetFavoriteNumbers()  return favoriteNumbers; 

// Methods
bool Student::LikesBlue() 
    return (male || age >= 10);

glue.cpp
// glue.cpp
// To use c++11, first run: Sys.setenv("PKG_CXXFLAGS"="-std=c++11")  ...or use a Makevars file

#include <Rcpp.h>
#include "Student.hpp"
using namespace Rcpp;

//' Simulate a student
//'
//' @export
// [[Rcpp::export]]
std::vector<int> simulate_student() 
  Student s = Student("bob", 10, true);
  return s.GetFavoriteNumbers();


// Expose (some of) the Student class
RCPP_MODULE(Student)
  class_<Student>("Student")
  .constructor<std::string,int,bool>()
  .method("LikesBlue", &Student::LikesBlue)
  ;

R/

学生.R
#' student
#'
#' A cool package
#'
#' Imports
#' @useDynLib student, .registration = TRUE
#' @importFrom Rcpp sourceCpp
"_PACKAGE"

Rcpp::loadModule(module = "Student", TRUE)

调用devtools::document()后,得到如下的NAMESPACE文件

命名空间
# Generated by roxygen2: do not edit by hand

export(simulate_student)
importFrom(Rcpp,sourceCpp)
useDynLib(student, .registration = TRUE)

现在,在从 RStudio(即R CMD INSTALL --preclean --no-multiarch --with-keep.source student)执行 clean and rebuild 之后,包编译和加载没有问题。如果我运行 simulate_student() 函数,我会得到预期的结果。但是,当我尝试使用 stud &lt;- new(Student) 创建一个新的 Student 对象时,我得到 Error in .getClassesFromCache(Class) : object 'Student' not found

这个问题似乎类似于this SO post,但接受的答案似乎并没有解决我的问题。此外,我查看了 Dirk 提到的Annoy source code,但我没有看到该代码与我的代码之间有任何有用的区别,除了我尝试在我的代码中放置但也这样做的RCPP_EXPOSED_CLASS_NODECL(AnnoyEuclidean) sn-ps没用。

【问题讨论】:

以this guide 为参考,我没有看到任何类型的unif_module &lt;- Module( "unif_module", getDynLib(fx_unif ) ) 语句来定义R 领域中的模块。 【参考方案1】:

看一下这两个包,主要区别在于函数的导入和导出是如何设置的。

尤其是methodsRcpp 包都作为NAMESPACE 文件中的完整导入 缺失。此外,不是单独导出每个函数,而是使用全局导出模式。

RcppAnnoy

useDynLib(RcppAnnoy, .registration=TRUE)
import(methods, Rcpp)
exportPattern("^[[:alpha:]]+")          # export all identifiers starting with letters

https://github.com/eddelbuettel/rcppannoy/blob/1ce871ae52730098ddc7355597613e8313e23ac9/NAMESPACE#L1-L3

Rcpp学生

氧气2:

#' @useDynLib RcppStudent, .registration = TRUE
#' @import methods Rcpp
#' @exportPattern "^[[:alpha:]]+"

NAMESPACE:

# Generated by roxygen2: do not edit by hand

exportPattern("^[[:alpha:]]+")
import(Rcpp)
import(methods)
useDynLib(RcppStudent, .registration = TRUE)

https://github.com/r-pkg-examples/rcpp-modules/blob/ca5d13ddd391d9fd4ffb50b4306131d2839f8af5/NAMESPACE#L5-L7

【讨论】:

【参考方案2】:

this SO post 的答案和 cmets 帮助了我。看来我需要

1) 将@importFrom Rcpp sourceCpp 更改为@import Rcpp 和 2) 将export(Student) 添加到我的 NAMESPACE 文件中(尽管我正在搜索如何使用 roxygen2 很好地做到这一点,而不是手动插入)

以上修改后我可以运行

> stud <- new(Student, name = "Ben", age = 26, male = T)
> stud$LikesBlue()
[1] TRUE

更新 看来我可以将#' @export Student 添加到student.R 以使roxygen 自动将export(Student) 位添加到我的NAMESPACE,这样我就不必手动修改NAMESPACE。

更新2 我在this blog post中记录了我的步骤

【讨论】:

非常感谢您记录了如此好的步骤!

以上是关于使用 Rcpp 模块向 R 公开简单的 C++ Student 类的主要内容,如果未能解决你的问题,请参考以下文章

使用 Rcpp 在 C++ 函数的 R 中使用 for 循环的内存问题

内存在简单的Rcpp函数中泄漏

如何分析 Rcpp 代码(在 linux 上)

在包 BAR 中使用 R 包 FOO 中的 C++ 代码的最佳方法

rcpp报错,在mac上学习Rcpp和C++

优化 R 代码 - Rcpp