Como incorporar C++ no R – {Rcpp}

Como usar o {Rcpp} para funções em C++ no R

Jose Storopoli https://scholar.google.com/citations?user=xGU7H1QAAAAJ&hl=en (UNINOVE)https://www.uninove.br
February 2, 2021

A maneira mais fácil e simples de usar código C++ no R é pelo pacote {Rccp}. O primeiro passo é importar o pacote:

Criando funções em C++ no R

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:

  1. sourceCpp(): lê código C++ de um arquivo .cpp ou de uma string.
  2. 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;

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

Como exibir mensagens e erros em funções {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;

cout << "Imprima algo na tela\n";
cerr << "Imprima um erro na tela\n";

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

Cancelando a Execução no {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 ...
}

Tipos de Dados e Variáveis do {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:

vec_int <- c(1L, 2L, 3L, 4L)
str(vec_int)
 int [1:4] 1 2 3 4
mat_num <- matrix(c(1.1, 2.2, 3.3, 4.4), nrow = 2, ncol = 2)
str(mat_num)
 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++

Lógica

logical

LogicalVector

LogicalMatrix

-

NA_LOGICAL

bool

Inteiro

integer

IntegerVector

IntegerMatrix

-

NA_INTEGER

int

Real

numeric

NumericVector

NumericMatrix

-

NA_REAL

double

Complexo

complex

ComplexVector

ComplexMatrix

Rcomplex

-

complex

String

character

CharacterVector (StringVector)

CharacterMatrix (StringMatrix)

String

NA_STRING

std::string

Date

Date

DateVector

-

Date

-

-

Datetime

POSIXct

DatetimeVector

-

Datetime

-

time_t

Além de vetores e matrizes, {Rcpp} também possui as estrutura de dados correspondentes ao data.frame e list:

R Rcpp

data.frame

DataFrame

list

List

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.

Criando Objetos de 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)
NumericVector v (3);

// v <- rep(1, 3)
NumericVector v (3,1);

// v <- c(1,2,3)
// C++11 Inicialização em Lista
NumericVector v = {1,2,3};

// v <- c(1,2,3)
NumericVector v = NumericVector::create(1,2,3);

// v <- c(x=1, y=2, z=3)
NumericVector v =
NumericVector::create(Named("x",1), Named("y")=2 , _["z"]=3);

a função Rcpp::Named() é usada para criar vetores (e outros objetos) nomeados e há 3 variações conforme demonstrado acima.

Acessando Elementos de 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
NumericVector v  {10,20,30,40,50};

// Designando nomes dos elementos
v.names() = CharacterVector({"A","B","C","D","E"});

// Extraindo valores dos elementos de Vector
double x1 = v[0];
double x2 = v["A"];

// Designando valores aos elementos de Vector
v[0]   = 100;
v["A"] = 100;

Métodos de Vector

Abaixo um exemplo dos principais métodos de Vector3. 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).

Operações com 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)
NumericMatrix m1(2);

// m <- matrix(0, nrow=2, ncol=3)
NumericMatrix m2(2 , 3);

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
NumericVector v = {1,2,3,4};

// Designa o número de linhas e colunas no atributo dim do objeto Vector
v.attr("dim") = Dimension(2, 2);

// 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
List L = List::create(Named("nome1") = v1 , _["nome2"] = v2);

{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
DataFrame df = DataFrame::create( Named("V1") = v1 , _["V2"] = v2 );

{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:

df <- tibble::tibble()
class(df)
[1] "tbl_df"     "tbl"        "data.frame"

E aí é só adicionar essas classes num DataFrame do {Rcpp}:

DataFrame df = DataFrame::create( Named("V1") = v1 , _["V2"] = v2 );
df.attr("class") = CharacterVector::create("tbl_df", "tbl", "data.frame");

Pronto seu objeto DataFrame quando for retornado ao R será uma tibble do {tidyverse}.

{Rcpp} Sugar

Alé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.

Exemplo – Multiplicação de Matrizes

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]]
NumericVector mat_mul(const NumericVector& A, const NumericVector& B) {
  NumericVector C = A * B;

  // dimensões para Vector virar Matrix no R
  int dim = sqrt(A.length());
  C.attr("dim") = Dimension(dim, dim);

  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  
Benchmarks de Multiplicação de Matriz: R vs C++

Figure 1: Benchmarks de Multiplicação de Matriz: R vs C++

Sucesso! Ganho de 200x 🤯

Usando a biblioteca padrão C++11 STL no {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++.

Exemplo – 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:

  1. sum_of_squares_R(): feita no R com vetorização.
  2. 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.
  3. 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.
  4. 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
Benchmarks de Soma dos Quadrados: R vs alternativas C++

Figure 2: Benchmarks de Soma dos Quadrados: R vs alternativas C++

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 Boost

Boost é 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:

Para usar o Boost no {Rcpp} também é muito simples:

  1. Certifique-se que você tem o pacote {BH} (Boost Headers) de R instalado.
  2. Inclua a síntaxe // [[Rcpp::depends(BH)]] em qualquer lugar do seu código C++.
  3. Inclua o header que deseja usar do boost no topo do seu código C++. Ex: #include <boost/header_qualquer.hpp>

Exemplo – Máximo Divisor Comum

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:

  1. rGDCD(): R usando o algoritmo de Euclides.
  2. cppGCD(): C++ usando std::gcd() do header <numeric> (C++17).
  3. 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
Benchmarks de Máximo Divisor Comum: R vs C++

Figure 3: Benchmarks de Máximo Divisor Comum: R vs C++

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 Rmarkdown

Para 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 Rmarkdown

Figure 4: {Rcpp} no Rmarkdown

Usar {Rcpp} no seu pacote R

Para adicionar {Rcpp} a um pacote existente, coloque seus arquivos C++ no diretório src/ e crie ou modifique os seguintes arquivos de configuração:

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").

Materiais Adicionais de Consulta

Diversos materiais me ajudaram a aprender e criar esse conjunto de tutoriais de {Rcpp}:

Ambiente

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   

  1. tem também o evalCpp() mas não vou cobrir aqui↩︎

  2. lembrando que C++ os índices começam em zero: então o primeiro elemento é Vector[0].↩︎

  3. quem conhece C++, em especial a C++11 STL, pode ver que muitos métodos de Vector são iguais à std::vector.↩︎

  4. verifique também como instalar um compilador C++ que dê suporte ao C++20 (talvez o g++ versão 10).↩︎

Corrections

If you see mistakes or want to suggest changes, please create an issue on the source repository.

Reuse

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 ...".

Citation

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}
}