【发布时间】:2019-07-31 17:19:27
【问题描述】:
我的情况是,我有一个指向 Armadillo 对象的 Rcpp::XPtr(例如 arma::Mat,它可能是一种受支持数据类型的矩阵)。现在我想编写一个查询元素数量的函数。到目前为止,我能想到的最好的方法如下(灵感来自 bigstatsr):
#define DISPATCH_DATA_TYPE(CALL) \
{ \
switch (data_type) \
{ \
case 1: CALL(unsigned short) \
case 2: CALL(unsigned int) \
case 3: CALL(unsigned long) \
case 4: CALL(short) \
case 5: CALL(int) \
case 6: CALL(long) \
case 7: CALL(float) \
case 8: CALL(double) \
default: throw Rcpp::exception("Unsupported data type."); \
} \
}
template <typename T>
arma::uword mat_length(SEXP mat)
{
Rcpp::XPtr< arma::Mat<T> > p(mat);
return p->n_elem;
}
#define MAT_LENGTH(TYPE) return mat_length<TYPE>(mat);
// [[Rcpp::export]]
arma::uword mat_length(SEXP mat, int data_type)
{
DISPATCH_DATA_TYPE(MAT_LENGTH)
}
有没有更好的方法来做到这一点?我将这种模式用于相当多的功能,并且冗长正在成为一个问题。理想情况下,我会有一个单一但简洁的功能,例如(当然不起作用)
arma::uword mat_length(SEXP mat)
{
Rcpp::XPtr<arma::Mat> p(mat);
return p->n_elem;
}
而不是两个函数 + 每个实例的宏,我将 XPtr 从 R 传递到 C。
额外问题:基于宏观的方法有什么明显的问题吗?这是否效率低下或可能导致问题?
要创建可重现的示例,请添加
// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>
// [[Rcpp::export]]
SEXP setup_mat(arma::uword n_rows, arma::uword n_cols)
{
arma::mat* res = new arma::mat(n_rows, n_cols);
return Rcpp::XPtr<arma::mat>(res);
}
并对 R 中的文件运行 Rcpp::sourceCpp()。
【问题讨论】:
-
我要说的第一件事是使用宏
#define DISPATCH_DATA_TYPE(CALL) {看起来很糟糕——你为什么要这样做而不是一个适当的(可能是constexpr)函数?第二;case 1: CALL(unsigned short) \ case 2: CALL(unsigned int) \ case 3: CALL(unsigned long)等等,这些真的应该落入下一个case吗?这看起来是错误的 - 我本来希望那里有一些break语句.. -
@JesperJuhl 感谢您对我的问题感兴趣。我看你不喜欢宏观方法。至于我为什么要这样做,恐怕我没有一个好的答案:我在某个地方看到了这个,并认为它会以合理的方式解决我的问题。这更像是一种审美厌恶,还是客观上对此有什么不好?如果您认为这应该以不同的方式进行,您会这么好心并草拟一个替代解决方案吗?缺少
breaks 有问题吗?CALLs 包含return语句。
标签: c++ templates rcpp rcpparmadillo