我正在使用Rcpp创建一个包,我希望有一个函数,而不是std::string
或int
作为参数。我该怎么办?
我有以下功能:
int myFunction(std::string varname);
RcppExport SEXP myFunction(SEXP varname) {
BEGIN_RCPP
Rcpp::RObject __result;
Rcpp::RNGScope __rngScope;
std::string myVarname = as<std::string>(varname);
__result = Rcpp::wrap(myFunction(myVarname));
return __result;
END_RCPP
}
int myFunction(int varname);
RcppExport SEXP myFunction(SEXP varname) {
BEGIN_RCPP
Rcpp::RObject __result;
Rcpp::RNGScope __rngScope;
int myVarname = as<int>(varname);
__result = Rcpp::wrap(myFunction(myVarname));
return __result;
END_RCPP
}
我已经实现了两个c ++函数(一个允许int
,另一个允许std::string
)
在我定义R函数的文件中:
myFunction <- function(varname) {
.Call('myFunction', PACKAGE = 'myPackage', varname)
}
当我构建我的包时,我收到以下错误:
RcppExports.cpp:78:17: error: redefinition of ‘SEXPREC* myFunction(SEXP)’
RcppExport SEXP myFunction(SEXP varname) {
^
RcppExports.cpp:67:17: note: ‘SEXPREC* myFunction(SEXP)’ previously defined here
RcppExport SEXP myFunction(SEXP varname) {
答案 0 :(得分:7)
正如Dirk在评论中指出的那样,这可以通过从(单个)导出函数中调度适当的实现函数来完成。典型方法涉及switch
语句和TYPEOF
宏,如下所示:
#include <Rcpp.h>
struct fallthrough {};
template <typename T>
int overloaded_impl(const T& t) {
return -1;
}
template <>
int overloaded_impl<std::string>(const std::string& x) {
return x.size();
}
template <>
int overloaded_impl<int>(const int& x) {
return x * 2;
}
// [[Rcpp::export]]
int overloaded(SEXP x) {
switch (TYPEOF(x)) {
case INTSXP: {
return overloaded_impl<int>(INTEGER(x)[0]);
}
case REALSXP: {
return overloaded_impl<int>((int)(REAL(x)[0]));
}
case STRSXP: {
std::string tmp = CHAR(STRING_ELT(x, 0));
return overloaded_impl<std::string>(tmp);
}
default: {
Rcpp::warning("Unmatched SEXPTYPE!");
return overloaded_impl<fallthrough>(fallthrough());
}
}
return -1; // not reached
}
/*** R
overloaded("a string")
#[1] 8
overloaded(10L)
#[1] 20
overloaded(10)
#[1] 20
overloaded(TRUE)
#[1] -1
#Warning message:
#In overloaded(TRUE) : Unmatched SEXPTYPE!
overloaded(2 + 2i)
#[1] -1
#Warning message:
#In overloaded(2 + (0+2i)) : Unmatched SEXPTYPE!
*/
case: REALSXP
就在那里,因为R默认为numeric
而不是integer
,例如没有它你会有:
overloaded(10)
#[1] -1
#Warning message:
#In overloaded(10) : Unmatched SEXPTYPE!
此策略的一种变体是创建一个包含变体对象的包装类,其中基于switch
的类型推导逻辑被移动到构造函数中,并且通过应用访问者模式来执行方法调度。这对于上面的简单示例来说并不合理,但是在您可以在对象上调用多个不同函数的情况下,它可以避免大量代码重复,因为switch(TYPEOF(x)) {...}
块不需要存在于每个功能中。 Here's an example我使用Boost C ++库在更大范围内完成了这项工作,由BH
包提供。
无论如何,我们可以使用variant / visitor技术重写原始示例,如下所示:
// [[Rcpp::depends(BH)]]
#include <Rcpp.h>
#include <boost/variant.hpp>
class variant {
private:
struct fallthrough {};
typedef boost::variant<
int,
std::string,
fallthrough
> variant_t;
variant_t v;
struct overloaded_visitor : public boost::static_visitor<int> {
int operator()(const std::string& x) const {
return x.size();
}
int operator()(const int& x) const {
return x * 2;
}
template <typename T>
int operator()(const T&) const {
return -1;
}
};
public:
variant(SEXP x)
{
switch (TYPEOF(x)) {
case INTSXP: {
v = variant_t(INTEGER(x)[0]);
break;
}
case REALSXP: {
v = variant_t((int)(REAL(x)[0]));
break;
}
case STRSXP: {
std::string tmp = CHAR(STRING_ELT(x, 0));
v = variant_t(tmp);
break;
}
default: {
Rcpp::warning("Unmatched SEXPTYPE!");
v = variant_t(fallthrough());
break;
}
}
}
int overloaded() const {
return boost::apply_visitor(overloaded_visitor(), v);
}
};
// [[Rcpp::export]]
int overloaded(SEXP x) {
return variant(x).overloaded();
}
/*** R
overloaded("a string")
#[1] 8
overloaded(10L)
#[1] 20
overloaded(12)
#[1] 24
overloaded(FALSE)
#[1] -1
#Warning messages:
#In overloaded(FALSE) : Unmatched SEXPTYPE!
overloaded(2 + 2i)
#[1] -1
#Warning messages:
#In overloaded(2 + (0+2i)) : Unmatched SEXPTYPE!
*/
答案 1 :(得分:2)
RcppExport是一个简单的#define RcppExport extern "C"
因此,myFunction具有类似C的命名约定。因此,它不能重载,因为在这种情况下你需要C ++样式的名称。