Search code examples
c++rrcpp

How do I check whether an IntegerVector contains NA values in Rcpp?


I wish to check that an Rcpp IntegerVector provided to a C++ function does not contain NA values.

Following another answer, I have written the below:

IntegerMatrix stop_if_na(const IntegerVector I) {
  if (Rcpp::is_true(Rcpp::any(Rcpp::IntegerVector::is_na(I)))) {
    Rcpp::stop("`I` contains NA values");
  }

But I see a compilation error:

note: candidate: 'template<bool NA, class T> bool Rcpp::is_na(const Rcpp::sugar::SingleLogicalResult<NA, T>&)'
      38 |  inline bool is_na( const Rcpp::sugar::SingleLogicalResult<NA,T>& x){
         |              ^~~~~
note:   template argument deduction/substitution failed:
   <file>.cpp:22:48 note:   'const IntegerVector' {aka 'const Rcpp::Vector<13, Rcpp::PreserveStorage>'} is not derived from 'const Rcpp::sugar::SingleLogicalResult<NA, T>'
      22 |   if (Rcpp::is_true(Rcpp::any(Rcpp::is_na(I)))) {
         |                                            ^

When I remove IntegerVector:: (as suggested by user20650 and Dirk Eddelbuettel) I see

error:  matching function for call to 'is_na(const IntegerVector&)
      20 |   if (Rcpp::is_true(Rcpp::any(Rcpp::is_na(I)
         |   

template argument deduction/substitution failed:
   <file>.cpp:20:48:note: 'const IntegerVector{aka 'const note: ndidate: 'template<bool NA, class T> bool Rcpp::is_na(const Rcpp::sugar::SingleLogicalResult<NA, T>&)
      38 |  inline bool is_nast Rcpp::sugar::SingleLogicalResult<NA,T>& x){
         |              ^~~~~
   note: template argument deduction/substitution failed:
<file>.cpp:20:48:note: 'const IntegerVector{aka 'const Rcpp::Vector<13, Rcpp::PreserveStorage> is not derived from 'const Rcpp::sugar::SingleLogicalResult<NA, T>
      20 |   if (Rcpp::is_true(Rcpp::any(Rcpp::is_na(I)
         |                                            ^

(As the C++ function is exported from a package, I can't rely on the calling R function to perform this test.)

sessionInfo() output

R Under development (unstable) (2022-07-19 r82607 ucrt)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 19044)

Matrix products: default

locale:
[1] LC_COLLATE=English_United Kingdom.utf8  LC_CTYPE=English_United Kingdom.utf8   
[3] LC_MONETARY=English_United Kingdom.utf8 LC_NUMERIC=C                           
[5] LC_TIME=English_United Kingdom.utf8    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

loaded via a namespace (and not attached):
 [1] htmlwidgets_1.5.4    compiler_4.3.0       microbenchmark_1.4.9 magrittr_2.0.3      
 [5] fastmap_1.1.0        cli_3.3.0            profvis_0.3.7        tools_4.3.0         
 [9] htmltools_0.5.3      rstudioapi_0.13      stringi_1.7.8        stringr_1.4.0       
[13] digest_0.6.29        rlang_1.0.4  

packageVersion("Rcpp") = 1.0.9


Solution

  • This is so core a feature that we had it more or less since day one, and I am a little surprised that you did not come across the very early Rcpp Gallery posts Working with Missing Values by Hadley from Dec 2012.

    Note that the more interesting features are 'Sugar' functions:

    > Rcpp::cppFunction("LogicalVector foo(NumericVector x) {return is_finite(x);}")
    > foo(c(1.0, Inf, -Inf, NA, NaN, 42))
    [1]  TRUE FALSE FALSE FALSE FALSE  TRUE
    > 
    

    There are a few related predicates you may want to look into.

    Your suggested function also works if you just remove the ::IntegerVector in the call:

    > Rcpp::cppFunction("void stop_if_na(const IntegerVector IV) {
    + if (Rcpp::is_true(Rcpp::any(Rcpp::is_na(IV)))) {
    + Rcpp::stop(\"`I` contains NA values\");
    + }
    + }")
    > stop_if_na(1:5)
    > stop_if_na(c(1:5, NA, 7:9))
    Error: `I` contains NA values
    > 
    

    For ease of re-use my code snippet follows.

    Rcpp::cppFunction("LogicalVector foo(NumericVector x) { return is_finite(x); }")
    foo(c(1.0, Inf, -Inf, NA, NaN, 42))
    
    
    Rcpp::cppFunction("void stop_if_na(const IntegerVector IV) {
      if (Rcpp::is_true(Rcpp::any(Rcpp::is_na(IV)))) {
        Rcpp::stop(\"`I` contains NA values\");
      }
    }")
    stop_if_na(1:5)
    stop_if_na(c(1:5, NA, 7:9))