我正在用Rcpp创建一个包,并且我想要一个函数,可以接受astd::string
或a作为参数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 ++函数(一个承认a int
,另一个承认a 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) {
正如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)) {...}
不必在每个函数中都存在该块,因此可以避免很多代码重复。这是一个示例,其中,我使用Boost C ++库在更大程度上做到了这一点,该BH
软件包由该包提供。
无论如何,我们可以使用变体/访问者技术来重写原始示例,如下所示:
// [[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!
*/
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句