Rcpp模块:具有相同参数数量的公开构造函数的Validator函数

时间:2017-03-03 12:43:30

标签: rcpp

我想公开一个带有Rcpp模块的C ++类,它有两个具有相同参数数量的构造函数。正如Rcpp modules插图中所记录的那样,这可以通过使用验证器函数作为.constructor的第二个参数来实现,类型为

typedef bool (*ValidConstructor)(SEXP*,int);

有人可以举例说明它应该如何使用吗?在小插图中,只有TODO注释,应该包含一个示例。

3 个答案:

答案 0 :(得分:4)

要跟进nrussell的回答,您可能希望从模板生成验证器,即

.constructor<int, int>( & typed_valid<int,int> )

你将用作:

typed_valid

显然,{{1}}函数模板可以直接用可变参数模板进行推广。

答案 1 :(得分:2)

根据以前我没有亲自使用过的免责声明,以下内容似乎有效:

#include <Rcpp.h>
using namespace Rcpp;

class Example {
public:
    Example(int x_, int y_)
        : x(x_), y(y_)
    {
        Rcout << __PRETTY_FUNCTION__ << "\n";
    }

    Example(std::string x_, std::string y_)
        : x(x_.size()), y(y_.size())
    {
        Rcout << __PRETTY_FUNCTION__ << "\n";
    }

    int add() const
    { return x + y; }

private:
    int x, y;
};

bool validate_int_int(SEXP* args, int nargs)
{ return TYPEOF(args[0]) == INTSXP && TYPEOF(args[1]) == INTSXP; }

bool validate_string_string(SEXP* args, int nargs)
{ return TYPEOF(args[0]) == STRSXP && TYPEOF(args[1]) == STRSXP; }

RCPP_MODULE(ExampleMod) {

    class_<Example>("Example")
        .constructor<int, int>(
            "(int, int) constructor",
            validate_int_int
        )
        .constructor<std::string, std::string>(
            "(string, string) constructor",
            validate_string_string
        )
        .method("add", &Example::add)
    ;
}

从R测试,

ex.int <- new(Example, 1L, 2L)
# Example::Example(int, int)

ex.string <- new(Example, "one", "two")
# Example::Example(std::string, std::string)

ex.int$add()
# [1] 3

ex.string$add()
# [1] 6 

validate_int_intvalidate_string_string的每一个中,我们只是针对相应构造函数的签名测试输入SEXP类型。

答案 2 :(得分:0)

遵循先前的答案,我发现通过使用cpp中的可变参数模板,可能存在通用验证器功能。

尽管有许多技术细节超出了本文的范围,但实现比我预期的要短。

template <typename... Types>
bool universal_validator(SEXP* args, int nargs) {
  return universal_validator<Types...>(args, nargs, 0);
}

template <typename T = void, typename... Types>
bool universal_validator(SEXP* args, int nargs, int idx) {
  if (idx>=nargs) return false;

  // optional type traits
  typedef typename Rcpp::traits::remove_const_and_reference<T>::type _Tp;

  return Rcpp::is<_Tp>(args[idx]) && universal_validator<Types...>(args, nargs, idx+1);
}

template <>
bool universal_validator<>(SEXP* args, int nargs, int idx) {
  return nargs == idx;
}

universal_validator的用法非常简单。给定Example类,RCPP_MODULE中的构造函数将如下所示。

RCPP_MODULE(example_module) {

  Rcpp::class_<Example>("Example")
  

  .constructor<int, int>("(int, int) constructor", 
                         universal_validator<int, int>)

  .constructor<std::string, std::string> ("(string, string) constructor",
                                          universal_validator<std::string, std::string>)
  .method("add", &Example::add)
  ;
}

只需在验证器模板中输入与构造函数相同的参数类型,例如universal_validator<int, int>可以胜任。只要为任何类型Rcpp::is<T>定义了T,它就可以工作。

来自github的源代码 SEXP newInstance( SEXP* args, int nargs )指示验证器必须同时检查SEXP*nargs的类型。因此,在所有函数中不仅要检查SEXP*的类型,还要检查其索引。

相关问题