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

bra_racing

我正在用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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

c可以声明两个具有相同名称,返回类型但参数不同的函数

C ++ Koenig(依赖于参数)查找:如果不同名称空间中的两个名称空间函数具有相同的参数类型怎么办?

是否可以创建具有两个具有相同名称的属性的类型?

我们可以定义两个具有相同名称但参数不同的函数吗?

如何实现两个具有相同名称但参数不同的JNI方法?

具有相同名称和不同模板参数的两个结构如何工作

Java-具有相同名称,相同参数的不同类型的两个方法,但是这些类型在层次结构上相关

LuaJ从两个不同的LuaScript中加载两个具有相同名称的函数

构建discord bot时,能否在discord.py中使用两个具有相同名称但参数不同的函数?

Java模板,如何使用两个具有相同名称和不同类型的类

两个使用相同名称类型的不同库

我们可以在Codeigniter控制器中创建两个具有相同名称的函数吗?

为什么在使用动态类型和动态绑定时,两个具有相同名称(属于不同类)的方法应具有相同的原型?

具有相同名称但参数和返回类型不同的虚函数

具有相同名称和参数,不同返回类型的C ++成员函数

推断显示两个具有相同名称的不同变量?

两个不同包装中具有相同名称的实体

减去两个具有相同名称不同索引的数据框

Python-行为-具有相同名称的两个不同步骤

具有相同名称范围的Excel上的两个不同的从属下拉列表

如何为具有相同名称(不同名称空间)的两个类处理MVC DisplayTemplates

具有相同名称的两个功能

具有相同名称的两个输入

两个具有相同名称的HTTP GET参数时的行为

参考具有相同名称空间和类型的两个DLL

Python中两个具有相同名称的函数

两个具有相同名称,相同版本但具有不同公钥的程序集

Spring Data:注入两个具有相同名称但两个不同包的存储库

为不同命名空间中具有相同名称的两个服务设置两个入口