Rcppインターフェイスを使ったクラスライブラリを作成するコード側で,たとえば
Rから受け取った SEXP 型 a は,以下のように Rcpp::RObjectクラスの派生クラスに変換する必要があるのだが,
Rcpp::NumericVector xa(a);
この xa はそのまま演算できる.
RcppExport SEXP convolve3cpp(SEXP a, SEXP b) { Rcpp::NumericVector xa(a); Rcpp::NumericVector xb(b); int n_xa = xa.size(), n_xb = xb.size(); int nab = n_xa + n_xb - 1; Rcpp::NumericVector xab(nab); for (int i = 0; i < n_xa; i++) for (int j = 0; j < n_xb; j++) xab[i + j] += xa[i] * xb[j]; return xab; }
これをRに返す際には,明示的に型変換する必要がないので,ついつい SEXP そのものだと誤解しそうになるが,あくまで
Rcpp::RObjectクラスのオブジェクトであることを忘れないようにしないと,妙な代入などをおこなってしまいそうになる.
ちなみに,伝統的な R API で,Rinternals.h を使う場合は,演算処理のためにポインタをとる.
SEXP convolve2(SEXP a, SEXP b) { R_len_t i, j, na, nb, nab; double *xa, *xb, *xab; SEXP ab; // 型を指定して保護 PROTECT(a = coerceVector(a, REALSXP)); PROTECT(b = coerceVector(b, REALSXP)); na = length(a); nb = length(b); nab = na + nb - 1; PROTECT(ab = allocVector(REALSXP, nab)); // C言語での演算のためポインタを取得 xa = REAL(a); xb = REAL(b); xab = REAL(ab); for(i = 0; i < nab; i++) xab[i] = 0.0; for(i = 0; i < na; i++) for(j = 0; j < nb; j++) xab[i + j] += xa[i] * xb[j]; UNPROTECT(3); //SEXP型なのでそのまま返却できる return(ab); }
Rdefines.h を使う場合も,演算処理のためにポインタをとる.
SEXP convolve2(SEXP a, SEXP b) { R_len_t i, j, na, nb, nab; double *xa, *xb, *xab; SEXP ab; // 数値型として保護し PROTECT(a = AS_NUMERIC(a)); PROTECT(b = AS_NUMERIC(b)); na = LENGTH(a); nb = LENGTH(b); nab = na + nb - 1; PROTECT(ab = NEW_NUMERIC(nab)); // Cの演算のためにポインタを取り出す xa = NUMERIC_POINTER(a); xb = NUMERIC_POINTER(b); xab = NUMERIC_POINTER(ab); // ポインタを通した計算 for(i = 0; i < nab; i++) xab[i] = 0.0; for(i = 0; i < na; i++) for(j = 0; j < nb; j++) xab[i + j] += xa[i] * xb[j]; UNPROTECT(3); // SEXP型なのでそのまま返却できる return(ab); }
と明示的にPROTECTが必要になる.