我想公开一个带有Rcpp模块的C ++类,它有两个具有相同参数数量的构造函数。正如Rcpp modules插图中所记录的那样,这可以通过使用验证器函数作为.constructor
的第二个参数来实现,类型为
typedef bool (*ValidConstructor)(SEXP*,int);
有人可以举例说明它应该如何使用吗?在小插图中,只有TODO注释,应该包含一个示例。
答案 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_int
和validate_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*
的类型,还要检查其索引。