Rcpp 模块:具有相同数量参数的公开构造函数的验证器函数
Rcpp modules: Validator function for exposed constructors with same number of parameters
我想公开一个带有 Rcpp 模块的 C++ class,它有两个具有相同数量参数的构造函数。如 Rcpp modules 小插图中所述,这可以通过使用验证器函数作为 .constructor
的第二个参数来实现,类型为
typedef bool (*ValidConstructor)(SEXP*,int);
有人可以举例说明应该如何使用它吗?在小插图中,只有一个 TODO 注释,其中应包含一个示例。
免责声明,我以前没有亲自使用过它,以下似乎有效:
#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_int
和 validate_string_string
中,我们只是根据相应构造函数的签名测试输入 SEXP
类型。
要跟进 nrussell 的回答,您可能需要从模板生成验证器,即
template <typename T0, typename T1>
bool typed_valid( SEXP* args, int nargs ){
return nargs == 2 && Rcpp::is<T0>(args[0]) && Rcpp::is<T1>(args[1]) ;
}
您将用作:
.constructor<int, int>( & typed_valid<int,int> )
显然 typed_valid
函数模板可以直接用可变参数模板进行概括。
沿着之前答案的脚步,我发现在 cpp
.
中使用可变参数模板有可能存在通用验证器函数
实施比我预期的要短,但有许多技术细节超出了本文的范围post。
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
class,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>
会完成这项工作。只要为任何类型 T
.
定义了 Rcpp::is<T>
,这就可以工作
来自github的源代码
SEXP newInstance( SEXP* args, int nargs ) 表示验证器必须同时检查 SEXP*
和 nargs
的类型。这就是为什么在所有函数中不仅要检查类型,还要检查 SEXP*
的索引。
我想公开一个带有 Rcpp 模块的 C++ class,它有两个具有相同数量参数的构造函数。如 Rcpp modules 小插图中所述,这可以通过使用验证器函数作为 .constructor
的第二个参数来实现,类型为
typedef bool (*ValidConstructor)(SEXP*,int);
有人可以举例说明应该如何使用它吗?在小插图中,只有一个 TODO 注释,其中应包含一个示例。
免责声明,我以前没有亲自使用过它,以下似乎有效:
#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_int
和 validate_string_string
中,我们只是根据相应构造函数的签名测试输入 SEXP
类型。
要跟进 nrussell 的回答,您可能需要从模板生成验证器,即
template <typename T0, typename T1>
bool typed_valid( SEXP* args, int nargs ){
return nargs == 2 && Rcpp::is<T0>(args[0]) && Rcpp::is<T1>(args[1]) ;
}
您将用作:
.constructor<int, int>( & typed_valid<int,int> )
显然 typed_valid
函数模板可以直接用可变参数模板进行概括。
沿着之前答案的脚步,我发现在 cpp
.
实施比我预期的要短,但有许多技术细节超出了本文的范围post。
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
class,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>
会完成这项工作。只要为任何类型 T
.
Rcpp::is<T>
,这就可以工作
来自github的源代码
SEXP newInstance( SEXP* args, int nargs ) 表示验证器必须同时检查 SEXP*
和 nargs
的类型。这就是为什么在所有函数中不仅要检查类型,还要检查 SEXP*
的索引。