通过 Rcpp 模块将用户定义的列表 class 从 C++ 公开到 R
Expose user defined list class from C++ to R via Rcpp modules
我用 C++ 编写了一个 class class_A 并使用 Rcpp 模块框架将其暴露给 R。工作起来非常棒。
#include "Rcpp.h"
using namespace Rcpp;
class class_A {
public:
class_A(double num){this->num = num;};
double get_num(){return this->num;};
private:
double num;
};
RCPP_MODULE(class_A_module) {
class_<class_A>("class_A")
.constructor<double>()
.property("num", &class_A::get_num)
;
}
RCPP_EXPOSED_CLASS(class_A);
现在我想要一个 class class_B 可以存储 class_A 的多个实例(以及一些其他属性)。为此,我的想法是使用 std::vector:
class class_B {
public:
class_B(std::vector<class_A> num_list){this->num_list = num_list;};
std::vector<class_A> get_num_list(){return this->num_list;};
private:
std::vector<class_A> num_list;
};
RCPP_MODULE(class_B_module) {
class_<class_B>("class_B")
.constructor<std::vector<class_A>>()
.property("num_list", &class_B::get_num_list)
;
}
RCPP_EXPOSED_CLASS(class_B);
无法编译:
no matching function for call to 'export_range__dispatch(SEXPREC*&,
__gnu_cxx::__normal_iterator<class_A*, std::vector<class_A>
>&, Rcpp::traits::r_type_traits<class_A>::r_category)'
这并不奇怪:Rcpp 应该如何将 std::vector 暴露给 R?
来自 this highly relevant rcpp-devel Mailing list thread I understood that it's nevertheless somehow possible to create this simple storage class class_B. I guess I have to write my own wrap
and as
implementation。
1.目前为止正确吗?
2. 对于我的简单代码示例,我该怎么做呢?我发现的所有示例都比我预期的最低限度实施要复杂得多。
编辑:
我修改了示例代码并试图找出问题所在。
Header 和实现现在分开了:
ex.h
class class_A {
public:
class_A(double num);
double get_num();
private:
double num;
};
class class_B {
public:
class_B(std::vector<class_A> num_list);
std::vector<class_A> get_num_list();
private:
std::vector<class_A> num_list;
};
ex.cpp
#include "Rcpp.h"
#include "ex.h"
using namespace Rcpp;
class_A::class_A(double num){this->num = num;}
double class_A::get_num(){return this->num;}
RCPP_MODULE(class_A_module) {
class_<class_A>("class_A")
.constructor<double>()
.property("num", &class_A::get_num)
;
}
RCPP_EXPOSED_CLASS(class_A);
class_B::class_B(std::vector<class_A> num_list){this->num_list = num_list;}
std::vector<class_A> class_B::get_num_list(){return this->num_list;}
RCPP_MODULE(class_B_module) {
class_<class_B>("class_B")
.constructor<std::vector<class_A>>()
.property("num_list", &class_B::get_num_list)
;
}
RCPP_EXPOSED_CLASS(class_B);
这是我实现 'wrap' 和 'as' 的尝试。
fix.cpp
#include <RcppCommon.h>
#include "ex.h"
// non-intrusive extension via template specialisation
namespace Rcpp {
template <> class_A as(SEXP aa);
template <> SEXP wrap(const class_A &a);
template <> class_B as(SEXP bb);
template <> SEXP wrap(const class_B &b);
}
#include <Rcpp.h>
// define template specialisations for as and wrap
namespace Rcpp {
template <> class_A as(SEXP aasexp) {
double aa = as<double>(aasexp);
return class_A(aa);
}
template <> SEXP wrap(const class_A &a) {
return Rcpp::wrap(a);
}
template <> class_B as(SEXP bbsexp) {
// ?
}
template <> SEXP wrap(const class_B &b) {
// ?
}
}
我想有趣的部分是我无法理解的部分?
一种方法是让构造函数采用 Rcpp::List
,或者如果您不想弄乱 class_B
的语义,则使用工厂:
class_B* class_B_ctor( List data){
std::vector<class_A> v ;
for( int i=0; i<data.size(); i++){
v.push_back( as<class_A>(data[i]) );
}
return new class_B(v) ;
}
您可以在模块中使用 .factory
方法:
RCPP_MODULE(class_A_module) {
class_<class_A>("class_A")
.constructor<double>()
.property("num", &class_A::get_num)
;
class_<class_B>("class_B")
.factory< List >( &class_B_ctor )
.property("num_list", &class_B::get_num_list)
;
}
这样:
> a1 <- new( class_A )
> a2 <- new( class_B )
> a1
C++ object <0x103008b78> of class 'class_A' <0x10e4bcd20>
> a2
C++ object <0x103008b78> of class 'class_B' <0x10e4bce20>
> new( class_B, list(a1,a2) )
C++ object <0x10e4de420> of class 'class_B' <0x10e4bce20>
我用 C++ 编写了一个 class class_A 并使用 Rcpp 模块框架将其暴露给 R。工作起来非常棒。
#include "Rcpp.h"
using namespace Rcpp;
class class_A {
public:
class_A(double num){this->num = num;};
double get_num(){return this->num;};
private:
double num;
};
RCPP_MODULE(class_A_module) {
class_<class_A>("class_A")
.constructor<double>()
.property("num", &class_A::get_num)
;
}
RCPP_EXPOSED_CLASS(class_A);
现在我想要一个 class class_B 可以存储 class_A 的多个实例(以及一些其他属性)。为此,我的想法是使用 std::vector:
class class_B {
public:
class_B(std::vector<class_A> num_list){this->num_list = num_list;};
std::vector<class_A> get_num_list(){return this->num_list;};
private:
std::vector<class_A> num_list;
};
RCPP_MODULE(class_B_module) {
class_<class_B>("class_B")
.constructor<std::vector<class_A>>()
.property("num_list", &class_B::get_num_list)
;
}
RCPP_EXPOSED_CLASS(class_B);
无法编译:
no matching function for call to 'export_range__dispatch(SEXPREC*&,
__gnu_cxx::__normal_iterator<class_A*, std::vector<class_A>
>&, Rcpp::traits::r_type_traits<class_A>::r_category)'
这并不奇怪:Rcpp 应该如何将 std::vector 暴露给 R?
来自 this highly relevant rcpp-devel Mailing list thread I understood that it's nevertheless somehow possible to create this simple storage class class_B. I guess I have to write my own wrap
and as
implementation。
1.目前为止正确吗?
2. 对于我的简单代码示例,我该怎么做呢?我发现的所有示例都比我预期的最低限度实施要复杂得多。
编辑: 我修改了示例代码并试图找出问题所在。
Header 和实现现在分开了:
ex.h
class class_A {
public:
class_A(double num);
double get_num();
private:
double num;
};
class class_B {
public:
class_B(std::vector<class_A> num_list);
std::vector<class_A> get_num_list();
private:
std::vector<class_A> num_list;
};
ex.cpp
#include "Rcpp.h"
#include "ex.h"
using namespace Rcpp;
class_A::class_A(double num){this->num = num;}
double class_A::get_num(){return this->num;}
RCPP_MODULE(class_A_module) {
class_<class_A>("class_A")
.constructor<double>()
.property("num", &class_A::get_num)
;
}
RCPP_EXPOSED_CLASS(class_A);
class_B::class_B(std::vector<class_A> num_list){this->num_list = num_list;}
std::vector<class_A> class_B::get_num_list(){return this->num_list;}
RCPP_MODULE(class_B_module) {
class_<class_B>("class_B")
.constructor<std::vector<class_A>>()
.property("num_list", &class_B::get_num_list)
;
}
RCPP_EXPOSED_CLASS(class_B);
这是我实现 'wrap' 和 'as' 的尝试。
fix.cpp
#include <RcppCommon.h>
#include "ex.h"
// non-intrusive extension via template specialisation
namespace Rcpp {
template <> class_A as(SEXP aa);
template <> SEXP wrap(const class_A &a);
template <> class_B as(SEXP bb);
template <> SEXP wrap(const class_B &b);
}
#include <Rcpp.h>
// define template specialisations for as and wrap
namespace Rcpp {
template <> class_A as(SEXP aasexp) {
double aa = as<double>(aasexp);
return class_A(aa);
}
template <> SEXP wrap(const class_A &a) {
return Rcpp::wrap(a);
}
template <> class_B as(SEXP bbsexp) {
// ?
}
template <> SEXP wrap(const class_B &b) {
// ?
}
}
我想有趣的部分是我无法理解的部分?
一种方法是让构造函数采用 Rcpp::List
,或者如果您不想弄乱 class_B
的语义,则使用工厂:
class_B* class_B_ctor( List data){
std::vector<class_A> v ;
for( int i=0; i<data.size(); i++){
v.push_back( as<class_A>(data[i]) );
}
return new class_B(v) ;
}
您可以在模块中使用 .factory
方法:
RCPP_MODULE(class_A_module) {
class_<class_A>("class_A")
.constructor<double>()
.property("num", &class_A::get_num)
;
class_<class_B>("class_B")
.factory< List >( &class_B_ctor )
.property("num_list", &class_B::get_num_list)
;
}
这样:
> a1 <- new( class_A )
> a2 <- new( class_B )
> a1
C++ object <0x103008b78> of class 'class_A' <0x10e4bcd20>
> a2
C++ object <0x103008b78> of class 'class_B' <0x10e4bce20>
> new( class_B, list(a1,a2) )
C++ object <0x10e4de420> of class 'class_B' <0x10e4bce20>