我想使用RCPP_MODULE禁用暴露给R的C ++类的默认(零参数)构造函数,以便在R中没有任何其他参数的情况下调用new(class)会产生错误。这是我尝试过的选项:
1)指定一个默认构造函数并在函数体中引发错误:这是我需要做的,但是意味着指定一个默认构造函数,该默认构造函数为所有const成员变量设置伪值(这对于我的实际用例而言是乏味的)
2)指定默认构造函数是私有的(没有定义):这意味着如果在Rcpp模块中使用.constructor(),则代码将不会编译,但是如果未使用.constructor(),则该代码将无效。在Rcpp模块中
3)在默认构造函数上明确使用delete:需要C ++ 11,并且似乎具有与(2)相同的效果(缺少)
我确定我缺少明显的东西,但我一生无法解决它。有人有什么想法吗?
预先感谢
马特
最小示例代码(在R中运行):
inc <- '
using namespace Rcpp;
class Foo
{
public:
Foo()
{
stop("Disallowed default constructor");
}
Foo(int arg)
{
Rprintf("Foo OK\\n");
}
};
class Bar
{
private:
Bar();
// Also has no effect:
// Bar() = delete;
public:
Bar(int arg)
{
Rprintf("Bar OK\\n");
}
};
RCPP_MODULE(mod) {
class_<Foo>("Foo")
.constructor("Disallowed default constructor")
.constructor<int>("Intended 1-argument constructor")
;
class_<Bar>("Bar")
// Wont compile unless this line is commented out:
// .constructor("Private default constructor")
.constructor<int>("Intended 1-argument constructor")
;
}
'
library('Rcpp')
library('inline')
fx <- cxxfunction(signature(), plugin="Rcpp", include=inc)
mod <- Module("mod", getDynLib(fx))
# OK as expected:
new(mod$Foo, 1)
# Fails as expected:
new(mod$Foo)
# OK as expected:
new(mod$Bar, 1)
# Unexpectedly succeeds:
new(mod$Bar)
如何在不求助于Foo的解决方案的情况下使new(mod $ Bar)失败?
编辑
我发现我的问题实际上是其他症状:
#include <Rcpp.h>
class Foo {
public:
int m_Var;
Foo() {Rcpp::stop("Disallowed default constructor"); m_Var=0;}
Foo(int arg) {Rprintf("1-argument constructor\n"); m_Var=1;}
int GetVar() {return m_Var;}
};
RCPP_MODULE(mod) {
Rcpp::class_<Foo>("Foo")
.constructor<int>("Intended 1-argument constructor")
.property("m_Var", &Foo::GetVar, "Get value assigned to m_Var")
;
}
/*** R
# OK as expected:
f1 <- new(Foo, 1)
# Value set in the 1-parameter constructor as expected:
f1$m_Var
# Unexpectedly succeeds without the error message:
tryCatch(f0 <- new(Foo), error = print)
# This is the type of error I was expecting to see:
tryCatch(f2 <- new(Foo, 1, 2), error = print)
# Note that f0 is not viable (and sometimes brings down my R session):
tryCatch(f0$m_Var, error = print)
*/
[向@RalfStubner致谢以提供改进的代码]
因此,实际上,似乎new(Foo)实际上根本没有为Foo调用任何C ++构造函数,所以我的问题有点离题了……抱歉。
我想没有办法防止在C ++级别上发生这种情况,因此也许最有意义的是在R级别上对new(Foo)的调用使用包装函数,或者继续指定一个默认构造函数,引发错误。这两个解决方案都可以正常工作-我只是好奇为什么我对缺少默认构造函数的期望是错误的:)
作为后续问题:是否有人确切知道上面的f0 <-new(Foo)中发生了什么?我有限的理解表明,尽管f0是在R中创建的,但关联的指针会导致某些东西(在C ++中尚未正确分配)?
答案 0 :(得分:1)
经过一些试验,我发现了一个简单的解决方案,回想起来很明显……!我要做的就是将.factory用作默认构造函数,以及一个不带参数且只会引发错误的函数。默认情况下,Class的默认构造函数从未实际引用过,因此不需要定义,但它在R中获得了所需的行为(即,如果用户错误地调用了new而没有附加参数,则会产生错误)。
以下是显示解决方案的示例(Foo_A)和更清晰的问题说明(Foo_B):
#include <Rcpp.h>
class Foo {
private:
Foo(); // Or for C++11: Foo() = delete;
const int m_Var;
public:
Foo(int arg) : m_Var(arg) {Rcpp::Rcout << "Constructor with value " << m_Var << "\n";}
void ptrAdd() const {Rcpp::Rcout << "Pointer: " << (void*) this << "\n";}
};
Foo* dummy_factory() {Rcpp::stop("Default constructor is disabled for this class"); return 0;}
RCPP_MODULE(mod) {
Rcpp::class_<Foo>("Foo_A")
.factory(dummy_factory) // Disable the default constructor
.constructor<int>("Intended 1-argument constructor")
.method("ptrAdd", &Foo::ptrAdd, "Show the pointer address")
;
Rcpp::class_<Foo>("Foo_B")
.constructor<int>("Intended 1-argument constructor")
.method("ptrAdd", &Foo::ptrAdd, "Show the pointer address")
;
}
/*** R
# OK as expected:
fa1 <- new(Foo_A, 1)
# Error as expected:
tryCatch(fa0 <- new(Foo_A), error = print)
# OK as expected:
fb1 <- new(Foo_B, 1)
# No error:
tryCatch(fb0 <- new(Foo_B), error = print)
# But this terminates R with the following (quite helpful!) message:
# terminating with uncaught exception of type Rcpp::not_initialized: C++ object not initialized. (Missing default constructor?)
tryCatch(fb0$ptrAdd(), error = print)
*/
正如我在评论中建议的那样,我在https://github.com/RcppCore/Rcpp/issues/970上开始了与此相关的讨论。