1

I am writing an Rcpp package with classes containing base Rcpp objects that are non-intrusively exported to C++ types (see Extending Rcpp by Eddelbuettel and Francois, and this helpful vignette by coatless).

What this means is that if I have a class foo::bar and a constructor for foo::bar given a SEXP, I can call a function like this:

//[[Rcpp::export]]
void func(foo::bar object){
   // do something
}

My problem is that sourceCpp("foobar.cpp") works exactly as expected, but R CMD build complains about the RcppExports.cpp file missing declarations for this new class.

Here is a minimum reproducible example, containing a foo::bar class holding a single Rcpp::NumericVector. It compiles with sourceCpp() but the package will not build because foobar is not found in RcppExports.cpp:

foobar.cpp:

#include <RcppCommon.h>

// forward declare class
namespace foo {
    class bar;
}

// forward declare Rcpp::as<> Exporter
template <>
class Rcpp::traits::Exporter<foo::bar>;

#include <Rcpp.h>

// now fully declare class, since Rcpp objects 
//   are now loaded from Rcpp.h
namespace foo {
    class bar {
        public:
        Rcpp::NumericVector x;
        bar(Rcpp::NumericVector x) : x(x) {};
    };
}

// now fully declare Rcpp exporter, since we can
//   deal with Rcpp objects from Rcpp.h
namespace Rcpp {
    namespace traits {
        template <>
        class Exporter<foo::bar> {
            Rcpp::NumericVector x_;

            public:
            Exporter(SEXP x) : x_(x) {}

            foo::bar get() {
                return foo::bar(x_);
            }
        };
    }
}

//[[Rcpp::export]]
Rcpp::NumericVector test(foo::bar& A) {
    return A.x;
}

The specific errors I am getting when running R CMD check are all in the src/RcppExports.cpp file:

  • 'foo' has not been declared
  • 'A' was not declared in this scope
  • 'foo' was not declared in this scope
  • 'template argument 1 is invalid
  • 'qualified-id in declaration before 'A'

What needs to happen to get the package to build just like sourceCpp?

Thanks for any solutions!

zdebruine
  • 3,687
  • 6
  • 31
  • 50

1 Answers1

3

RcppExports.cpp file missing declarations for this new class.

See the Attributes vignette. The custom behavior is to have a header named as the package (i.e. foo.h for package foo) and/or foo-types.h) which will be added to the generated RcppExports.cpp.

That is documented but hidden rather too effectively :-/ It's here too so we could close this as a dupe but I don't have time to search that now.

Dirk Eddelbuettel
  • 360,940
  • 56
  • 644
  • 725
  • 1
    Thanks @DirkEddelbuettel! Well documented indeed but hidden effectively. This is awesome, and it really helps out with the RcppSparse package I'm working on, and a functional Rcpp sparse matrix class header should now be on CRAN in short order. – zdebruine Nov 03 '21 at 22:27
  • 1
    Awesome! And congrats on getting RcppClock -- haven't had a chance to look at it though. – Dirk Eddelbuettel Nov 04 '21 at 00:13
  • always happy to write a vignette for RcppGallery on RcppClock. It's actually quite fun to benchmark pieces of Rcpp code with C++ timers and get the results delivered right into the R session at runtime :) – zdebruine Nov 06 '21 at 14:05
  • 1
    I once "started" (in the sense of an initial test package) two benchmark packages based on C++ infrastructure. But it seems hard / impossible / real work to get the data 'back up into R' so I never progressed. The initial exploratioins still on github in rcppgeiger and rcppbenchmark ... So yes, if you have an interesting point to make or illustrate the Gallery is always listening :) – Dirk Eddelbuettel Nov 06 '21 at 14:46
  • Just submitted a PR on RcppGallery. To get the data "back up into R" I just use Rcpp to create a data.frame (well, S3 class) as a global variable in the R environment. It's pretty simple really -- wrap std::chrono::high_resolution clock on the C++ side, write a few S3 methods on the R side. Seems like you went a bit deeper with rcppgeiger on the benchmarking side, I'm sure one can do better than just wrapping calls to C++ chrono. – zdebruine Nov 06 '21 at 16:38