且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

使用 Rcpp 属性允许 C++ 常量作为默认函数参数

更新时间:2022-04-03 02:08:16

简而言之,是的,这是可能的,但它需要技巧,包括创建中间函数或在主函数中嵌入排序逻辑.

In short, yes its possible but it requires finesse that involves creating an intermediary function or embedding sorting logic within the main function.

总而言之,Rcpp 属性仅支持值的限制特征集.这些值列在 Rcpp 常见问题解答中3.12入口

In long, Rcpp attributes only supports a limit feature set of values. These values are listed in the Rcpp FAQ 3.12 entry

  • 用引号分隔的字符串文字(例如foo")
  • 整数和十进制数值(例如 10 或 4.5)
  • 预定义常量包括:
    • 布尔值:true 和 false
    • 空值:R_NilValue、NA_STRING、NA_INTEGER、NA_REAL 和 NA_LOGICAL.
    • CharacterVector、IntegerVector 和 NumericVector
    • CharacterMatrix、IntegerMatrix 和 NumericMatrix)

    如果您要为 LLONG_MAXLLONG_MIN 指定数值,这将满足直接在函数上使用 Rcpp 属性的条件.但是,这些值是特定于实现的.因此,对它们进行硬编码并不理想.因此,我们必须寻求外部解决方案:Rcpp::Nullable 类以启用默认的 NULL 值.之所以要用Rcpp::Nullable来包裹参数类型,是因为NULL很特殊,不小心会让人心痛.

    If you were to specify numerical values for LLONG_MAX and LLONG_MIN this would meet the criteria to directly use Rcpp attributes on the function. However, these values are implementation specific. Thus, it would not be ideal to hardcode them. Thus, we have to seek an outside solution: the Rcpp::Nullable<T> class to enable the default NULL value. The reason why we have to wrap the parameter type with Rcpp::Nullable<T> is that NULL is a very special and can cause heartache if not careful.

    NULL 值与实数轴上的其他值不同,在这种情况下将不会用于绑定您的值.因此,它是用于函数调用的完美候选者.然后您必须做出两个选择:使用 Rcpp::Nullable 作为主函数的参数,或者创建一个具有正确参数并可在其他地方使用的逻辑"辅助函数在您的应用程序中,无需担心.我选择了下面的后者.

    The NULL value, unlike others on the real number line, will not be used to bound your values in this case. As a result, it is the perfect candidate to use on the function call. There are two choices you then have to make: use Rcpp::Nullable<T> as the parameters on the main function or create a "logic" helper function that has the correct parameters and can be used elsewhere within your application without worry. I've opted for the later below.

    #include <Rcpp.h>
    #include <float.h>
    #include <cmath>
    #include <climits> //for LLONG_MIN and LLONG_MAX
    using namespace Rcpp;
    
    NumericVector cumsum_bounded_logic(NumericVector x,
                                       long long int upper = LLONG_MAX,
                                       long long int lower = LLONG_MIN) {
    
        NumericVector res(x.size());
        double acc = 0;
        for (int i=0; i < x.size(); ++i) {
            acc += x[i];
            if (acc < lower)  acc = lower;
            else if (acc > upper)  acc = upper;
            res[i] = acc;
        }
    
        return res;
    }
    
    // [[Rcpp::export]]
    NumericVector cumsum_bounded(NumericVector x,
                                 Rcpp::Nullable<long long int> upper = R_NilValue, 
                                 Rcpp::Nullable<long long int> lower = R_NilValue) {
    
        if(upper.isNotNull() && lower.isNotNull()){
            return cumsum_bounded_logic(x, Rcpp::as< long long int >(upper), Rcpp::as< long long int >(lower));
        } else if(upper.isNull() && lower.isNotNull()){
            return cumsum_bounded_logic(x, LLONG_MAX, Rcpp::as< long long int >(lower));
        } else if(upper.isNotNull() && lower.isNull()) {
            return cumsum_bounded_logic(x, Rcpp::as< long long int >(upper), LLONG_MIN);
        } else {
            return cumsum_bounded_logic(x, LLONG_MAX, LLONG_MIN);
        }
    
        // Required to quiet compiler
        return x;
    }
    

    测试输出


    Test Output

    cumsum_bounded(a, 5)
    ## [1] 1 2 3 4 5 5 5
    cumsum_bounded(a, 5, 2)
    ## [1] 2 3 4 5 5 5 5