gpt4 book ai didi

c++ - 创建两个具有相同名称但参数类型不同的 R 函数

转载 作者:可可西里 更新时间:2023-11-01 18:27:07 25 4
gpt4 key购买 nike

我正在用 Rcpp 创建一个包,我想要一个可以接受 std::stringint 作为参数的函数。我该怎么做?

我有以下功能:

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) {

最佳答案

正如德克在评论中指出的那样,这可以通过从(单个)导出函数中分派(dispatch)适当的实现函数来完成。典型的方法涉及 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) ) {...} block 不需要存在于每个函数中。 Here's an exampleBH 包的帮助下,我使用 Boost C++ 库在更大范围内完成了这项工作。

无论如何,我们可以使用变体/访问者技术重写原始示例,如下所示:

// [[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!

*/

关于c++ - 创建两个具有相同名称但参数类型不同的 R 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37023726/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com