#r #rcpp #r-package #s-expression
Вопрос:
Я пишу пакет Rcpp с классами, содержащими базовые объекты Rcpp, которые ненавязчиво экспортируются в типы C (см. Расширение Rcpp от Eddelbuettel и Франсуа и эту полезную виньетку от coatless).
Это означает , что если у меня есть класс foo::bar
и конструктор для foo::bar
данного a SEXP
, я могу вызвать функцию, подобную этой:
//[[Rcpp::export]]
void func(foo::bar object){
// do something
}
Моя проблема в том, что это sourceCpp("foobar.cpp")
работает точно так, как ожидалось, но R CMD build
жалуется на RcppExports.cpp
отсутствие в файле объявлений для этого нового класса.
Вот минимальный воспроизводимый пример, содержащий foo::bar
класс, содержащий один Rcpp::NumericVector
. Он компилируется с sourceCpp()
, но пакет не будет собран, потому foobar
что не найден в 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::baramp; A) {
return A.x;
}
Конкретные ошибки, которые я получаю при запуске R CMD check
, все в src/RcppExports.cpp
файле:
- «фу» не было объявлено
- «А» не было объявлено в этой области
- «foo» не был объявлен в этой области
- ‘аргумент шаблона 1 недопустим
- ‘квалифицированный идентификатор в декларации перед «А»
Что должно произойти, чтобы пакет создавался точно так sourceCpp
же ?
Спасибо за любые решения!
Ответ №1:
RcppExports.cpp файл отсутствующих объявлений для этого нового класса.
См.виньетку Атрибутов. Пользовательское поведение заключается в том, чтобы заголовок назывался пакетом (т. Е. foo.h
для пакета foo
) и/или foo-types.h
), который будет добавлен в сгенерированный RcppExports.cpp
.
Это задокументировано, но скрыто слишком эффективно :-/ Это тоже здесь, так что мы могли бы закрыть это как обман, но у меня нет времени искать это сейчас.
Комментарии:
1. Спасибо @DirkEddelbuettel! Действительно, хорошо задокументировано, но эффективно скрыто. Это потрясающе, и это действительно помогает с пакетом RcppSparse, над которым я работаю, и функциональный заголовок класса разреженной матрицы Rcpp теперь должен быть в CRAN в кратчайшие сроки.
2. Классно! И поздравляю с получением RcppClock-хотя у меня не было возможности взглянуть на него.
3. всегда рад написать виньетку для RcppGallery на RcppClock. На самом деле довольно забавно сравнивать фрагменты кода Rcpp с помощью таймеров C и получать результаты прямо в сеансе R во время выполнения 🙂
4. Однажды я «запустил» (в смысле начального тестового пакета) два тестовых пакета, основанных на инфраструктуре C . Но кажется трудной / невозможной / реальной работой вернуть данные «обратно в R», поэтому я так и не продвинулся. Первоначальные исследования все еще находятся на github в rcppgeiger и rcppbenchmark … Так что да, если у вас есть интересное замечание или иллюстрация, Галерея всегда готова вас выслушать 🙂
5. Только что отправил пиар на RcppGallery. Чтобы получить данные «обратно в R», я просто использую Rcpp для создания data.frame (ну, класса S3) в качестве глобальной переменной в среде R. На самом деле это довольно просто-оберните часы std::chrono::high_resolution на стороне C , напишите несколько методов S3 на стороне R. Похоже, вы пошли немного глубже с rcppgeiger на стороне сравнительного анализа, я уверен, что можно сделать лучше, чем просто перенос вызовов в C chrono.