【问题标题】:returning a custom object from a wrapped method in Rcpp从 Rcpp 中的包装方法返回自定义对象
【发布时间】:2012-09-13 11:53:47
【问题描述】:

我对 Rcpp 模块有以下问题: 假设我在 Rcpp 模块中有两个类

class A {
  public:
    int x;
};

class B
  public:
    A get_an_a(){
      A an_a();
      an_a.x=3;
      return an_a;
    }
};

RCPP_MODULE(mod){
  using namespace Rcpp ;
  class_<A>("A")
   .constructor()
   .property("x",&A::get_x)
  ;
  class_<B>("B)
   .constructor()
   .method("get_an_A",&get_an_a)
  ;
}

.

现在编译失败,因为它不知道如何处理 A 的返回类型。

我想我可以用 Rcpp::Xptr 做点什么,但是,我无法将它连接到 Rcpp 为 A 类生成的 S4 结构。我实际上从 R 中的方法获得了一个外部指针对象。

是否有可能从第二类的方法中获取正确包装的对象?

谢谢, 托马斯

[编辑]

根据 Dirk 的回答,我构造了一个可以创建被包装的 S4 对象的包装器:

template <> SEXP wrap(const A &obj) { // insprired from "make_new_object" from Rcpp/Module.h
  Rcpp::XPtr<A> xp( new A(obj), true ) ; // copy and mark as finalizable
  Function maker=Environment::Rcpp_namespace()[ "cpp_object_maker"];
  return maker ( typeid(A).name() , xp );
}

不过,我不知道如何将对象作为参数返回给方法/函数。以下方法不起作用:

template <> A* as( SEXP obj){
  Rcpp::List l(obj);
  Rcpp::XPtr<A> xp( (SEXP) l[".pointer"] );
  return (A*) xp;
}

那么如何从参数列表中作为 SEXP 提​​供的 S4 对象中获取指向 C++ 对象的外部指针?

【问题讨论】:

    标签: c++ r module rcpp


    【解决方案1】:

    此功能已在 Rcpp 0.10.0 中添加

    您的代码无法编译还有其他原因。下面的代码对我有用:

    class A {
      public:
        A(int x_) : x(x_){}
    
        int x;
    };
    
    class B {
      public:
        A get_an_a(){
          A an_a(3);
          return an_a;
        }
    };
    RCPP_EXPOSED_CLASS(A)
    RCPP_EXPOSED_CLASS(B)
    
    RCPP_MODULE(stackmod){
      using namespace Rcpp ;
      class_<A>("A")
       .constructor<int>()
       .field("x",&A::x)
      ;
      class_<B>("B")
       .constructor()
       .method("get_an_A",&B::get_an_a)
      ;
    }
    

    付出的代价是为所有类调用宏RCPP_EXPOSED_CLASS

    • 您的一个模块正在暴露
    • 您想作为公开方法的结果或作为参数使用

    有了这个,我得到:

    > b <- new( B )
    > b$get_an_A( )
    C++ object <0x10330a9d0> of class 'A' <0x1006f46e0>
    > b$get_an_A( )$x
    [1] 3
    

    【讨论】:

      【解决方案2】:

      如果你为它写一个包装器是可能的。那些不会像天上掉下来的吗哪,你需要通过提供它来帮助编译器,然后它就会被选中。

      来自 RcppBDT 的简单示例:

      template <> SEXP wrap(const boost::gregorian::date &d) {
          // convert to y/m/d struct
          boost::gregorian::date::ymd_type ymd = d.year_month_day();     
          return Rcpp::wrap(Rcpp::Date( ymd.year, ymd.month, ymd.day ));
      }
      

      这里一个来自 Boost 的类被转换为一个 Rcpp 类(Date),然后返回(即使在那里我们也需要一个显式包装)。对于更复杂的类,您需要更复杂的转换器。

      编辑:当然,您需要记住,任何可从 R 调用的东西仍然需要符合 .Call() 规定的基本 SEXP foo(SEXP a, SEXP b, ...) 接口。

      【讨论】:

      • 德克,感谢您的快速回复。不幸的是,只有当我可以将 A 转换为 R 类型并使用 wrap() 和 as() 函数来调解调用时,您的解决方案才会起作用。但是,我真正想要的是 Rcpp 为 A 类创建的包装类 (&lt;S4 object of class structure("Rcpp_A", package = "mod" )&gt; - 我认为)。当我从 R 调用 a&lt;-new(A) 时,我试图追踪执行此操作的构造函数,但无法找到。所以我想我只需要创建与构造函数相同的数据结构,然后可以在包装器中完成。我说的对吗?
      • 我不知道。如果您需要真正的帮助,请将可复制的内容发布到邮件列表中。鉴于您提供的三行代码,几乎不可能说出任何有意义的内容。
      • 嗨,Dirk,我部分想通了。我可以将包装的对象返回给 R。我编辑了问题并在那里发布了代码。不过,我不知道如何访问 S4 对象中的 C++ 对象。我希望我上面发布的代码能让我的问题更清楚一些。
      • 查看其他回复。 Rcpp > 0.9.15 可以。
      【解决方案3】:

      好的,我想我明白了。但没有任何保证。 根据 Dirk 的回答,我构建了一个可以创建包装的 S4 对象的包装器:

      template <> SEXP wrap(const A &obj) { // insprired from "make_new_object" from Rcpp/Module.h
        Rcpp::XPtr<A> xp( new A(obj), true ) ; // copy and mark as finalizable
        Function maker=Environment::Rcpp_namespace()[ "cpp_object_maker"];
        return maker ( typeid(A).name() , xp );
      }
      

      如果一个方法期望一个对象作为参数(这里是一个指向该对象的指针),下面的“as”包装器可能有用:

      template <> A* as( SEXP obj){
        Rcpp::Environment e(obj);
        Rcpp::XPtr<A> xp( (SEXP) e.get(".pointer") );
        return (A*) xp;
      }
      

      您当然也可以返回 *xp ,它允许将非指针作为参数,但这会再次复制对象。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-11-12
        • 2020-10-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多