Предоставить пользовательский список класса от C++ до R через модули Rcpp

Я написал класс class_A на C++ и использую инфраструктуру модулей 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_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?

Из этого весьма актуального потока рассылки rcpp-devel я понял, что тем не менее возможно создать этот простой класс хранения class_B. Я думаю, я должен написать свой собственный wrap а также as реализация.

1. Это правильно до сих пор?

2. Как мне это сделать в случае моего простого примера кода? Все примеры, которые я обнаружил, намного сложнее, чем я ожидаю, когда потребуется минимальная реализация.


Изменить: я изменил свой пример кода и попытался точно определить проблему.

Заголовок и реализация теперь разделены:

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);

Вот моя попытка реализовать "обтекание" и "как".

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) {
    // ?
  }
}

Я думаю, интересные части - это те, которые я не могу понять?

1 ответ

Решение

Одним из способов было бы иметь конструктор, принимающий 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>
Другие вопросы по тегам