Como usar o {Rcpp}
para funções em C++ no R
A maneira mais fácil e simples de usar código C++ no R é pelo pacote {Rccp}
. O primeiro passo é importar o pacote:
No {Rcpp}
é possível criarmos funções de duas maneiras1, sendo que ambas retornam as funções criadas em C++ para o ambiente do R:
sourceCpp()
: lê código C++ de um arquivo .cpp
ou de uma string
.cppFunction()
: cria uma função C++ de uma string
.sourceCpp()
Todo código C++ que é utilizado pelo {Rcpp}
deve começar com duas instruções no arquivo (ou string
do código):
#include <Rcpp.h>
using namespace Rcpp;
#include <Rcpp.h>
– indica que deve ser incluído o cabeçalho (header) do {Rcpp}
no arquivo. Isto permite com que o código faça a interface com o R usando o {Rcpp}
.using namespace Rcpp;
– importa todos os nomes que estão incluídos dentro da biblioteca {Rcpp}
. Para os que namespace
em C++. Isto evita conflitos de nome. Caso queira usar algo de uma namespace
você pode fazer de duas maneiras:
namespace
e acessar o nome desejado da namespace
com os quatro pontos (::
). Exemplo:// toda vez que usar List tem que indicar que é o List do Rcpp. Rcpp::List
using
. Exemplo:using Rcpp::List;
// toda vez que você digitar List C++ entende que é o List do Rcpp. List
Além disso, para cada função que for criada no código C++ é necessário incluir o // [[Rcpp::export]]
logo acima da função. Isto é necessário pois indica ao {Rcpp}
que a função deve ser exportada de volta para uso no ambiente do R. No exemplo abaixo criei uma função addCpp()
logo depois do Rcpp::export
:
// [[Rcpp::export]]
int addCpp(int x, int y, int z){
int result = x + y + z;
return result;
}
Há duas maneiras de usar sourceCpp()
: fornecendo um arquivo .cpp
ou um código C++ como string
.
sourceCpp()
– Usando um arquivo .cpp
Criei um arquivo chamado addCpp.cpp
com o código C++ pronto para ser usado pelo {Rcpp}
com o sourceCpp()
. Note que inclui um bloco de código R que automaticamente será executado após a compilação do arquivo. O ideal é inserir esses blocos de código R na parte final dos seus arquivos .cpp
.
writeLines(readLines("addCpp.cpp"))
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
int addCpp(int x, int y, int z){
int result = x + y + z;
return result;
}
// Você pode incluir blocos de códigos de R em código C++
// (útil para testagem e desenvolvimento). O código R será
// automaticamente executado após a compilação.
//
/*** R
addCpp(11, 21, 31)
*/
sourceCpp(file = "addCpp.cpp")
> addCpp(11, 21, 31)
[1] 63
sourceCpp()
– Usando uma string
Da mesma maneira que usamos sourceCpp()
para um arquivo .cpp
, também é possível usar uma string
em código C++. Abaixo o mesmo exemplo anterior, mas usando uma string
:
sourceCpp(code = "
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
int addCpp(int x, int y, int z){
int result = x + y + z;
return result;
}
/*** R
addCpp(11, 21, 31)
*/
")
> addCpp(11, 21, 31)
[1] 63
cppFunction()
cppFunction()
faz a mesma coisa que sourceCpp()
: retorna uma função criada em C++ para o ambiente do R. Mas com uma pequena diferença: você pode omitir todas as instruções do {Rcpp}
– o #include <Rcpp.h>
, using namespase Rcpp;
e // [[Rcpp::export]]
.
Usarei o mesmo exemplo do sourceCpp()
, sendo que agora não preciso mais incluir as instruções do {Rcpp}
:
cppFunction("
int addCpp(int x, int y, int z){
int result = x + y + z;
return result;
}
")
addCpp(1, 2, 4)
[1] 7
{Rcpp}
Tradicionalmente, em C++, usamos o cabeçalho <iostream>
da C++11 STL para imprimir na tela mensagens (cout
) e erros cerr
:
#include <iostream>
using std::cout;
using std::cerr;
"Imprima algo na tela\n";
cout << "Imprima um erro na tela\n"; cerr <<
Isto não funciona muito bem quando executamos uma função C++ no R com o {Rcpp}
. Para isso existem dois objetos na namespace
Rcpp
: Rcout
e Rcerr
. Veja um exemplo:
writeLines(readLines("teste_print.cpp"))
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
void teste_print(){
Rcout << "Imprima algo na tela\n";
Rcerr << "Imprima um erro na tela\n";
}
sourceCpp("teste_print.cpp")
teste_print()
Imprima algo na tela
{Rcpp}
A função CheckUserInterrupt()
do {Rcpp}
verifica se o botão ctrl + c
foi pressionado e, se for pressionado, interromperá a execução da função.
Se você quiser executar um cálculo que leve muito tempo, seria melhor executar checkUserInterrupt()
aproximadamente uma vez a cada poucos segundos. Veja este exemplo de um loop for
:
for (int i=0; i<100000; ++i) {
// Checando interrupção a cada 1000 iterações
if (i % 1000 == 0){
Rcpp::checkUserInterrupt();
}
// instruções do loop ...
}
{Rcpp}
Temos sete tipos de variáveis que são usualmente usados no R: logical
, integer
, numeric
,complex
, character
, Date
e POSIXct
. Sendo que esses sete tipos são usados no R para construir vetores (arrays
1-D) e matrizes (arrays
2-D). Apenas um lembrete:
int [1:4] 1 2 3 4
num [1:2, 1:2] 1.1 2.2 3.3 4.4
{Rcpp}
possui tipos de vetores e matrizes para representar correspondentemente aos do R.
A tabela abaixo apresenta a correspondência dos tipos de dados entre R/{Rcpp}
/C++:
Tipo de Variável | Vetor R | Vetor Rcpp | Matriz Rcpp | Escalar Rcpp | Missing Rcpp | Escalar C++ |
---|---|---|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Além de vetores e matrizes, {Rcpp}
também possui as estrutura de dados correspondentes ao data.frame
e list
:
R | Rcpp |
---|---|
|
|
|
|
No {Rcpp}
, Vector
, DataFrame
, List
são todos implementados como tipos de vetores. Ou seja, Vector
é um vetor em que seus elementos são valores escalares, DataFrame
é um vetor em que seus elementos são Vector
, List
é um vetor em que seus elementos são qualquer tipo de tipo de dados. Portanto, Vector
, DataFrame
, List
tem muitas funcionalidades em comum.
Muito importante: {Rcpp}
converterá qualquer tipo de retorno das funções para o seu respectivo tipo em R. Por exemplo, NumericVector
será convertido para um vetor de numeric
no R. Assim como LogicalMatrix
será convertida para uma matriz de logical
no R.
{Rcpp}
– Vector
Vector
no {Rcpp}
são arrays
1-D com tamanho dinâmico (não-estático). Note que Vector
é um objeto dentro do namespace
Rcpp
.
Vector
Veja alguns exemplos de como criar objetos de Vector
com o código em R correspondente comentado com //
:
// Crie um objeto Vector equivalente a
// v <- rep(0, 3)
3);
NumericVector v (
// v <- rep(1, 3)
3,1);
NumericVector v (
// v <- c(1,2,3)
// C++11 Inicialização em Lista
1,2,3};
NumericVector v = {
// v <- c(1,2,3)
1,2,3);
NumericVector v = NumericVector::create(
// v <- c(x=1, y=2, z=3)
NumericVector v ="x",1), Named("y")=2 , _["z"]=3); NumericVector::create(Named(
a função Rcpp::Named()
é usada para criar vetores (e outros objetos) nomeados e há 3 variações conforme demonstrado acima.
Vector
Você pode acessar um elemento individual de um objeto Vector
usando o operador []
ou ()
2 Ambos os operadores aceitam NumericVector
/IntegerVector
(índice numérico), CharacterVector
(nomes de elementos) e LogicalVector
. O operador []
ignora o acesso fora do limite, enquanto o operador ()
lança uma exceção index_out_of_bounds
.
Você pode também usar o método .names()
do Vector
para designar nomes ao elementos.
// Criando o Vector v
10,20,30,40,50};
NumericVector v {
// Designando nomes dos elementos
"A","B","C","D","E"});
v.names() = CharacterVector({
// Extraindo valores dos elementos de Vector
double x1 = v[0];
double x2 = v["A"];
// Designando valores aos elementos de Vector
0] = 100;
v["A"] = 100; v[
Vector
Abaixo um exemplo dos principais métodos de Vector
3. Lembrando que muitas dessas funcionalidades são compartilhadas com Matrix
, List
e DataFrame
. Para uma lista completa dos métodos das classes de {Rcpp}
recomendo a documentação não-oficial de {Rcpp}
do James Balamuta (também conhecido como TheCoatlessProfessor).
length()
, size()
names()
fill(x)
sort()
push_back(x)
, push_front(x)
, insert(i, x)
, erase(i)
Vector
Além de métodos, os elementos Vector
possuem alguns operadores:
+
,-
, *
, /
==
, !=
, <
, >
, >=
, <=
!
{Rcpp}
– Matrix
Matrix
no {Rcpp}
são arrays
2-D com tamanho estático. Note que Matrix
é um objeto dentro do namespace
Rcpp
.
A criação dos objetos Matrix
é similar à criação de objetos Vector
. Veja alguns exemplos de como criar objetos de Matrix
com o código em R correspondente comentado com //
:
// Criação de um objeto Matrix equivalente a
// m <- matrix(0, nrow=2, ncol=2)
2);
NumericMatrix m1(
// m <- matrix(0, nrow=2, ncol=3)
2 , 3); NumericMatrix m2(
Você pode acessar os elementos da mesma forma que Vector.
Além disso, um objeto Matrix
em R é na verdade um vetor cujo número de linhas e colunas é definido no atributo dim.
Portanto, se você criar um vetor com o atributo dim
em {Rcpp}
e devolvê-lo a R, ele será tratado como uma matriz:
// Criação de um objeto Vector
1,2,3,4};
NumericVector v = {
// Designa o número de linhas e colunas no atributo dim do objeto Vector
"dim") = Dimension(2, 2);
v.attr(
// Valor de retorno. Será tratado como uma matriz no R
return v;
{Rcpp}
– List
Em {Rcpp}
, objetos List
são implementados como uma espécie de Vector
. Em outras palavras, Vector
é um vetor cujo elemento é um valor escalar, enquanto List
é um vetor cujos elementos são quaisquer tipos de dados. Portanto, Vector
e List
geralmente têm as mesmas funcionalidades.
Para criar um objeto List
, usamos a função List::create()
. Além disso, para especificar o nome do elemento ao criar List
, use a função Named()
ou _[]
:
// Criação de um objeto List L dos vetores v1, v2
List L = List::create(v1, v2);
// Criação atribuindo nomes aos elementos da Lista L
"nome1") = v1 , _["nome2"] = v2); List L = List::create(Named(
{Rcpp}
– DataFrame
Em {Rcpp}
, objetos DataFrame
também são implementados como uma espécie de Vector
. Em outras palavras, Vector
é um vetor cujos elementos são valores escalares e DataFrame
é um vetor cujos elementos são Vector
. Portanto, DataFrame
tem muitas funcionalidades em comum com Vector
.
DataFrame::create()
é usado para criar um objeto DataFrame
. Além disso, use Named()
ou _[]
se desejar especificar os nomes das colunas ao criar o objeto DataFrame
:
// Criação de um objeto DataFrame df dos vetores v1, v2
DataFrame df = DataFrame::create(v1, v2);
// Criação atribuindo nomes às colunas de DataFrame df
"V1") = v1 , _["V2"] = v2 ); DataFrame df = DataFrame::create( Named(
{Rcpp}
tibble
Para retornar uma tibble
do {tidyverse}
com o {Rcpp}
é só você notar que uma tibble
não é nada mais que um data.frame
com algumas classes extras:
E aí é só adicionar essas classes num DataFrame
do {Rcpp}
:
"V1") = v1 , _["V2"] = v2 );
DataFrame df = DataFrame::create( Named("class") = CharacterVector::create("tbl_df", "tbl", "data.frame"); df.attr(
Pronto seu objeto DataFrame
quando for retornado ao R será uma tibble
do {tidyverse}
.
{Rcpp}
SugarAlém dos tipos de dados, {Rcpp}
também tem uma ampla gama de “açúcares” sintáticos (syntactic sugar) para as mais variadas operações e funções. Antes de tentar criar algo do zero veja se não há um {Rccp}
Sugar para isso já implementado na vinheta.
Está na hora de colocarmos o que vimos em prática. Nesse caso vamos comparar multiplicar duas matrizes usando o R (operador %*%
) e usando o C++ com {Rcpp}
.
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
const NumericVector& A, const NumericVector& B) {
NumericVector mat_mul(
NumericVector C = A * B;
// dimensões para Vector virar Matrix no R
int dim = sqrt(A.length());
"dim") = Dimension(dim, dim);
C.attr(
return C;
}
b1 <- bench::press(
n = 10^c(2:3),
{
X = matrix(rnorm(n * n), nrow = n)
bench::mark(
R = X %*% X,
Cpp = mat_mul(X, X),
check = FALSE,
relative = TRUE
)}
)
b1
# A tibble: 4 x 7
expression n min median `itr/sec` mem_alloc `gc/sec`
<bch:expr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 R 100 70.0 72.1 1 1 1
2 Cpp 100 1 1 58.2 1.03 76.3
3 R 1000 692. 307. 1 1 NaN
4 Cpp 1000 1 1 309. 1.00 Inf
Sucesso! Ganho de 200x 🤯
{Rcpp}
Caso queira usufruir da biblioteca padrão C++11 STL no {Rcpp}
é simples: basta incluir // [[Rcpp::plugins("cpp11")]]
em qualquer parte do seu código C++.
Caso queira usufruir da biblioteca padrão C++20 STL no {Rcpp}
é também simples: basta incluir // [[Rcpp::plugins("cpp2a")]]
4 em qualquer parte do código C++.
std::transforme_reduce()
Aqui eu vou ser um pouco abusado no exemplo e já vou pular direto para um algoritmo relativamente novo no mundo da STL de C++ (e um dos meus preferidos…). No mundo das linguagens de programação ele é conhecimento como MapReduce
, mas em C++ chama-se transform_reduce()
e está disponível no header <numeric>
desde C++17.
Soma dos quadrados é algo que ocorre bastante em computação científica, especialmente quando estamos falando de regressão, mínimos quadrados, ANOVA etc. Vamos fazer três implementações de uma função que aceita como parâmetro um vetor de números reais (C++ double
/ R numeric
) e computa a soma de todos os elementos do vetor elevados ao quadrado:
sum_of_squares_R()
: feita no R com vetorização.sum_of_squares_rcpp()
: feita de maneira ingênua no C++ com dois loops for
triviais que (1) multiplica cada elemento consigo mesmo e (2) adiciona todos os elementos do vetor à uma variável double
.sum_of_squares_rcpp20()
: solução elegante que usa transform_reduce
para transformar todos os elementos multiplicando-os por si mesmos e ao mesmo tempo somando todos os elementos.sum_of_squares_rcpp_sugar()
: solução usando {Rcpp}
Sugar.sum_of_squares_R <- function(v) {
sum(v * v)
}
#include <Rcpp.h>
// [[Rcpp::plugins("cpp11")]]
// [[Rcpp::plugins("cpp2a")]]
#include <numeric>
using namespace Rcpp;
// [[Rcpp::export]]
double sum_of_squares_rcpp(NumericVector v){
double sum_of_elems = 0;
// primeiro for multiplicando cada elemento consigo mesmo
for(int i=0; i < v.size(); i++){
v[i] = v[i] * v[i];
}
// segundo for somando todos os elementos
for(auto it = v.cbegin(); it != v.cend(); ++it)
sum_of_elems += *it;return sum_of_elems;
}
// [[Rcpp::export]]
double sum_of_squares_rcpp20(const NumericVector v){
return transform_reduce(v.cbegin(),
v.cend(),0L,
std::plus{},
auto i) {return i * i;});
[] (
}
// [[Rcpp::export]]
double sum_of_squares_rcpp_sugar(NumericVector v){
return(sum(v*v));
}
set.seed(123)
b2 <- bench::press(
n = 10^c(1:4),
{
v = rnorm(n)
bench::mark(
R = sum_of_squares_R(v),
rcpp = sum_of_squares_rcpp(v),
rcpp20 = sum_of_squares_rcpp20(v),
rcppsugar = sum_of_squares_rcpp_sugar(v),
check = FALSE,
relative = TRUE
)
})
b2
# A tibble: 16 x 7
expression n min median `itr/sec` mem_alloc `gc/sec`
<bch:expr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 R 10 1 1 1.84 NaN NaN
2 rcpp 10 2.13 2.01 1 Inf NaN
3 rcpp20 10 1.95 1.89 1.06 Inf Inf
4 rcppsugar 10 1.98 1.88 1.07 Inf NaN
5 R 100 1 1 1.99 1 NaN
6 rcpp 100 2.11 1.99 1 3.01 Inf
7 rcpp20 100 1.57 1.51 1.31 3.01 Inf
8 rcppsugar 100 1.62 1.55 1.30 3.01 NaN
9 R 1000 1.31 1.32 2.74 3.15 Inf
10 rcpp 1000 3.44 3.64 1 1 Inf
11 rcpp20 1000 1 1 3.59 1 NaN
12 rcppsugar 1000 1.23 1.22 2.96 1 Inf
13 R 10000 2.43 2.51 2.47 31.4 Inf
14 rcpp 10000 8.41 8.28 1 1 NaN
15 rcpp20 10000 1 1 8.31 1 Inf
16 rcppsugar 10000 1.74 1.79 4.15 1 NaN
Aqui vemos como a vetorização do R funciona muito bem. É mais rápida que quase todas as implementações em {Rcpp}
, exceto quando usamos o {Rcpp}
Sugar já que temos um ganho de 2x.
{Rcpp}
e BoostBoost é um conjunto de bibliotecas para a linguagem de programação C++ que fornece suporte para tarefas e estruturas como álgebra linear, geração de números pseudo-aleatórios, multithreading, processamento de imagem, expressões regulares e teste de unidade. Ele contém uma porrada 164 bibliotecas individuais (versão 1.75) e sua versão inicial foi lançada em 1999.
A maioria das bibliotecas Boost são licenciadas sob a Licença de Software Boost, projetada para permitir que Boost seja usado com projetos de software proprietários e gratuitos. Muitos dos fundadores da Boost estão no comitê internacional de padrões C++, e várias bibliotecas Boost foram aceitas para incorporação no padrão C++11 (por exemplo, smart pointers, thread
, regex
, random
, ratio
, tuple
) e no padrão C++17 (por exemplo, filesystem
, any
, optional
, variant
, string_view
).
Antes de usar o Boost no {Rcpp}
certifique-se que você tem o Boost instalado no seu sistema operacional:
sudo apt-get install libboost-all-dev
brew install boost
choco install boost-msvc-14.1
Para usar o Boost no {Rcpp}
também é muito simples:
{BH}
(Boost Headers) de R instalado.// [[Rcpp::depends(BH)]]
em qualquer lugar do seu código C++.#include <boost/header_qualquer.hpp>
O Máximo Divisor Comum (MDC), em inglês Greatest Common Divisor (GCD), de dois ou mais inteiros, que não são todos zero, é o maior inteiro positivo que divide cada um dos inteiros. Três abordagens:
rGDCD()
: R usando o algoritmo de Euclides.cppGCD()
: C++ usando std::gcd()
do header <numeric>
(C++17).boostGCD()
: C++ usando a biblioteca boost::integer
.rGCD <- function(a, b) {
if (a == 0) {
b
}
else {
rGCD(b %% a, a)
}
}
#include <Rcpp.h>
// [[Rcpp::plugins("cpp11")]]
// [[Rcpp::plugins("cpp17")]]
// [[Rcpp::depends(BH)]]
#include <numeric>
#include <boost/integer/common_factor_rt.hpp>
using namespace Rcpp;
// [[Rcpp::export]]
int cppGCD(int& a, int& b){
return std::gcd(a, b);
}
// [[Rcpp::export]]
int boostGCD(int& a, int& b) {
return boost::integer::gcd(a, b);
}
a <- 7919
b <- 7412
b3 <- bench::mark(
R = rGCD(a, b),
cpp = cppGCD(a, b),
boost = boostGCD(a, b),
relative = TRUE
)
b3
# A tibble: 3 x 6
expression min median `itr/sec` mem_alloc `gc/sec`
<bch:expr> <dbl> <dbl> <dbl> <dbl> <dbl>
1 R 4.05 4.17 1 6.29 1
2 cpp 1.03 1.02 3.94 1 1.97
3 boost 1 1 4.02 1 2.01
Aqui eu escolhi um número primo bem grande, 7189, e um número aleatório próximo dele, 7412. Como vocês podem ver a solução usando a biblioteca boost::integer
é 4,5x mais rápida que uma implementação em R e similar com a implementação de C++17.
{Rcpp}
e RmarkdownPara usar o {Rcpp}
em documentos rmarkdown basta colocar Rcpp
no chunk ao invés de r
. Sendo que no Rmarkdown não é necessário incluir as instruções do {Rcpp}
– o #include <Rcpp.h>
ou using namespace Rcpp;
, isto já é feito automático para você.
{Rcpp}
no seu pacote RPara adicionar {Rcpp}
a um pacote existente, coloque seus arquivos C++ no diretório src/
e crie ou modifique os seguintes arquivos de configuração:
No DESCRIPTION
adicione:
LinkingTo: Rcpp
Imports: Rcpp
Certifique-se de que seu NAMESPACE
inclua:
useDynLib(mypackage)
importFrom(Rcpp, sourceCpp)
A maneira mais fácil de configurar isso automaticamente é usar a função usethis::use_rcpp()
.
Antes de dar build
do pacote, você precisará executar Rcpp::compileAttributes()
. Esta função verifica os arquivos C++ em busca de atributos Rcpp::export
e gera o código necessário para disponibilizar as funções em R. Execute novamente compileAttributes()
sempre que as funções forem adicionadas, removidas ou seus nomes forem alterados. Isso é feito automaticamente pelo pacote {devtools}
e pelo Rstudio.
Para obter mais detalhes, consulte a vinheta do pacote {Rcpp}
, vignette("Rcpp-package")
.
Diversos materiais me ajudaram a aprender e criar esse conjunto de tutoriais de {Rcpp}
:
{Rcpp}
Dirk Eddelbuettel.{Rcpp}
.{Rcpp}
Sugar.{Rcpp}
do James Balamuta (também conhecido como TheCoatlessProfessor).{Rcpp}
.R version 4.0.4 (2021-02-15)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 20.10
Matrix products: default
BLAS: /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.9.0
LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.9.0
locale:
[1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
[3] LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
[5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
[7] LC_PAPER=en_US.UTF-8 LC_NAME=C
[9] LC_ADDRESS=C LC_TELEPHONE=C
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
attached base packages:
[1] stats graphics grDevices utils datasets methods
[7] base
other attached packages:
[1] dplyr_1.0.5 gt_0.2.2 Rcpp_1.0.6
loaded via a namespace (and not attached):
[1] tidyselect_1.1.0 xfun_0.22 bslib_0.2.4
[4] purrr_0.3.4 colorspace_2.0-0 vctrs_0.3.6
[7] generics_0.1.0 htmltools_0.5.1.1 emo_0.0.0.9000
[10] yaml_2.2.1 utf8_1.1.4 rlang_0.4.10
[13] jquerylib_0.1.3 pillar_1.5.1 glue_1.4.2
[16] DBI_1.1.1 lifecycle_1.0.0 stringr_1.4.0
[19] munsell_0.5.0 commonmark_1.7 gtable_0.3.0
[22] ragg_1.1.1 bench_1.1.1 evaluate_0.14
[25] knitr_1.31 parallel_4.0.4 fansi_0.4.2
[28] highr_0.8 profmem_0.6.0 scales_1.1.1
[31] backports_1.2.1 checkmate_2.0.0 debugme_1.1.0
[34] jsonlite_1.7.2 farver_2.1.0 systemfonts_1.0.1
[37] textshaping_0.3.2 distill_1.2 png_0.1-7
[40] ggplot2_3.3.3 digest_0.6.27 stringi_1.5.3
[43] grid_4.0.4 BH_1.75.0-0 cli_2.3.1
[46] tools_4.0.4 magrittr_2.0.1 sass_0.3.1
[49] tibble_3.1.0 crayon_1.4.1 tidyr_1.1.3
[52] pkgconfig_2.0.3 downlit_0.2.1 ellipsis_0.3.1
[55] lubridate_1.7.10 assertthat_0.2.1 rmarkdown_2.7
[58] rstudioapi_0.13 R6_2.5.0 compiler_4.0.4
tem também o evalCpp()
mas não vou cobrir aqui↩︎
lembrando que C++ os índices começam em zero: então o primeiro elemento é Vector[0]
.↩︎
quem conhece C++, em especial a C++11 STL, pode ver que muitos métodos de Vector
são iguais à std::vector
.↩︎
verifique também como instalar um compilador C++ que dê suporte ao C++20 (talvez o g++ versão 10).↩︎
If you see mistakes or want to suggest changes, please create an issue on the source repository.
Text and figures are licensed under Creative Commons Attribution CC BY-SA 4.0. Source code is available at https://github.com/storopoli/Rcpp, unless otherwise noted. The figures that have been reused from other sources don't fall under this license and can be recognized by a note in their caption: "Figure from ...".
For attribution, please cite this work as
Storopoli (2021, Feb. 2). Rcpp - A interface entre R e C++: Como incorporar C++ no R -- `{Rcpp}`. Retrieved from https://storopoli.github.io/Rcpp/2-Rcpp.html
BibTeX citation
@misc{storopoli2021rcpp, author = {Storopoli, Jose}, title = {Rcpp - A interface entre R e C++: Como incorporar C++ no R -- `{Rcpp}`}, url = {https://storopoli.github.io/Rcpp/2-Rcpp.html}, year = {2021} }