【发布时间】:2022-01-05 01:10:33
【问题描述】:
我有一个使用 Rcpp 模块向 R 公开的 C++ 代码库。具体来说,我使用了一种接口模式,其中我公开的类实际上是底层对象之上的一个抽象层,即实现。
我正在处理的类也相互交互,并且具有将对象的共享指针作为参数的方法。我无法找出将这些方法暴露给 R 的正确方法。
例如,这里有一些代码。 TestClass::combine 方法接受一个指向另一个 TestClass 对象的指针并使用它来处理。当我尝试编译这段代码时,当我将相应的接口方法ITestClass::combine 添加到模块时,会出现编译器错误(见下文)。
实施:
class TestClass
{
public:
TestClass(int const& n, double const& x)
: n(n), x(x)
{}
const double get_x() {
return x;
}
double combine(std::shared_ptr<TestClass> obj) {
return x + obj->get_x();
}
protected:
int n;
double x;
};
界面:
//' @export ITestClass
class ITestClass
{
public:
ITestClass(int const& in_n, double const& in_x)
: impl(in_n, in_x)
{}
double get_x() {
return impl.get_x();
}
double combine(ITestClass obj) {
return impl.combine(obj.get_object_ptr());
}
std::shared_ptr<TestClass> get_object_ptr() {
std::shared_ptr<TestClass> ptr(&impl);
return ptr;
}
private:
TestClass impl;
};
RCPP_MODULE(RTestClassModule)
{
class_<ITestClass>("ITestClass")
.constructor<int, double>()
.method("get_x", &ITestClass::get_x, "get_x")
.method("combine", &ITestClass::combine, "combine"); // this line errors out
}
我得到的错误示例:
In file included from C:/Rlib/Rcpp/include/Rcpp/as.h:25,
from C:/Rlib/Rcpp/include/RcppCommon.h:168,
from C:/Rlib/Rcpp/include/Rcpp.h:27,
from interface1.cpp:2:
C:/Rlib/Rcpp/include/Rcpp/internal/Exporter.h: In instantiation of 'Rcpp::traits::Exporter<T>::Exporter(SEXP) [with T = testpkg::ITestClass; SEXP = SEXPREC*]':
C:/Rlib/Rcpp/include/Rcpp/as.h:87:41: required from 'T Rcpp::internal::as(SEXP, Rcpp::traits::r_type_generic_tag) [with T = testpkg::ITestClass; SEXP = SEXPREC*]'
C:/Rlib/Rcpp/include/Rcpp/as.h:152:31: required from 'T Rcpp::as(SEXP) [with T = testpkg::ITestClass; SEXP = SEXPREC*]'
C:/Rlib/Rcpp/include/Rcpp/InputParameter.h:34:43: required from 'Rcpp::InputParameter<T>::operator T() [with T = testpkg::ITestClass]'
C:/Rlib/Rcpp/include/Rcpp/module/Module_generated_CppMethod.h:111:69: required from 'SEXPREC* Rcpp::CppMethod1<Class, RESULT_TYPE, U0>::operator()(Class*, SEXPREC**) [with Class = testpkg::ITestClass; RESULT_TYPE = double; U0 = testpkg::ITestClass; SEXP = SEXPREC*]'
C:/Rlib/Rcpp/include/Rcpp/module/Module_generated_CppMethod.h:109:10: required from here
C:/Rlib/Rcpp/include/Rcpp/internal/Exporter.h:31:31: error: no matching function for
call to 'testpkg::ITestClass::ITestClass(SEXPREC*&)'
Exporter( SEXP x ) : t(x){}
^
interface1.cpp:17:5: note: candidate: 'testpkg::ITestClass::ITestClass(SEXP, const int&, const double&)'
ITestClass(SEXP in_date, int const& in_n, double const& in_x)
^~~~~~~~~~
interface1.cpp:17:5: note: candidate expects 3 arguments, 1 provided
interface1.cpp:14:7: note: candidate: 'constexpr testpkg::ITestClass::ITestClass(const testpkg::ITestClass&)'
class ITestClass
^~~~~~~~~~
interface1.cpp:14:7: note: no known conversion for argument 1 from 'SEXP' {aka 'SEXPREC*'} to 'const testpkg::ITestClass&'
interface1.cpp:14:7: note: candidate: 'constexpr testpkg::ITestClass::ITestClass(testpkg::ITestClass&&)'
interface1.cpp:14:7: note: no known conversion for argument 1 from 'SEXP' {aka 'SEXPREC*'} to 'testpkg::ITestClass&&'
如何定义 ITestClass::combine 以便可以从 R 中调用它?
【问题讨论】:
-
另外,如果可能的话,我不想将
TestClass暴露给R。这就是接口层的用途,R 不应该知道也不关心实现。 -
tje 对象来自哪里(这里:一个 Rcpp Modules sn-p)并不重要,重要的是 R 只允许我们使用
.Call(SEXP a, SEXP b, ....)所以我们需要映射到 R 的 @ 987654330@。其中有整个其他小插图(R Extending)专用于它。 -
@DirkEddelbuettel 我很清楚 Rcpp 必须在 1990 年代 R API 的约束下工作。事实上,当他们抱怨时,我正在向他们解释这一点。但我仍然需要一个比我所拥有的更好的解决方案(这实际上是错误的,因为共享指针在使用 1 次后会破坏
obj2中的对象)。 -
成员函数
double combine(ITestClass obj)根本不适合SEXP .Call(SEXP a, SEXP b, ...)模具直到您通过C++ 代码为ITestClass提供包装器。编译器无法为您传递此信息,因此出现错误。 -
对,我知道这就是为什么我在回答中将其更改为
combine(SEXP)。但是如果我可以直接传递对象obj2,而不是obj2$get_object(),那就太好了。也许有办法在 C++ 中拆分obj2的结构?