forked from RcppCore/Rcpp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRcpp-modules.Rmd
1353 lines (1048 loc) · 37 KB
/
Rcpp-modules.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
---
title: |
| Exposing \proglang{C++} functions and classes
| with \pkg{Rcpp} modules
# Use letters for affiliations
author:
- name: Dirk Eddelbuettel
affiliation: a
- name: Romain François
affiliation: b
address:
- code: a
address: \url{http://dirk.eddelbuettel.com}
- code: b
address: \url{https://romain.rbind.io/}
# For footer text
lead_author_surname: Eddelbuettel and François
# Place DOI URL or CRAN Package URL here
doi: "https://cran.r-project.org/package=Rcpp"
# Abstract
abstract: |
This note discusses \textsl{Rcpp modules}. \textsl{Rcpp modules} allow programmers to
expose \proglang{C++} functions and classes to \proglang{R} with relative
ease. \textsl{Rcpp modules} are inspired from the \pkg{Boost.Python}
\proglang{C++} library \citep{Abrahams+Grosse-Kunstleve:2003:Boost.Python}
which provides similar features for \proglang{Python}.
# Optional: Acknowledgements
# acknowledgements: |
# Optional: One or more keywords
keywords:
- Rcpp
- modules
- R
- C++
# Font size of the document, values of 9pt (default), 10pt, 11pt and 12pt
fontsize: 9pt
# Optional: Force one-column layout, default is two-column
#one_column: true
# Optional: Enables lineo mode, but only if one_column mode is also true
#lineno: true
# Optional: Enable one-sided layout, default is two-sided
#one_sided: true
# Optional: Enable section numbering, default is unnumbered
numbersections: true
# Optional: Specify the depth of section number, default is 5
#secnumdepth: 5
# Optional: Bibliography
bibliography: Rcpp
# Optional: Enable a 'Draft' watermark on the document
#watermark: false
# Customize footer, eg by referencing the vignette
footer_contents: "Rcpp Vignette"
# Omit \pnasbreak at end
skip_final_break: true
# Produce a pinp document
output: pinp::pinp
header-includes: >
\newcommand{\proglang}[1]{\textsf{#1}}
\newcommand{\pkg}[1]{\textbf{#1}}
\newcommand{\faq}[1]{FAQ~\ref{#1}}
\newcommand{\rdoc}[2]{\href{http://www.rdocumentation.org/packages/#1/functions/#2}{\code{#2}}}
\newcommand{\sugar}{\textsl{Rcpp sugar}~}
\newcommand{\ith}{\textsl{i}-\textsuperscript{th}}
vignette: >
%\VignetteIndexEntry{Rcpp-modules}
%\VignetteKeywords{Rcpp, modules, R, Cpp}
%\VignettePackage{Rcpp}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
---
# Motivation
Exposing \proglang{C++} functionality to \proglang{R} is greatly facilitated
by the \pkg{Rcpp} package and its underlying \proglang{C++} library
\citep{CRAN:Rcpp,JSS:Rcpp}. \pkg{Rcpp} smoothes many of the rough edges in
\proglang{R} and \proglang{C++} integration by replacing the traditional
\proglang{R} Application Programming Interface (API) described in
'\textsl{Writing R Extensions}' \citep{R:Extensions} with a consistent set of \proglang{C++}
classes. The '\textsl{Rcpp-jss-2011}' vignette \citep{CRAN:Rcpp,JSS:Rcpp} describes the API and
provides an introduction to using \pkg{Rcpp}.
These \pkg{Rcpp} facilities offer a lot of assistance to the programmer
wishing to interface \proglang{R} and \proglang{C++}. At the same time, these
facilities are limited as they operate on a function-by-function basis. The
programmer has to implement a `.Call` compatible function (to
conform to the \proglang{R} API) using classes of the \pkg{Rcpp} API as
described in the next section.
## Exposing functions using \pkg{Rcpp}
Exposing existing \proglang{C++} functions to \proglang{R} through \pkg{Rcpp}
usually involves several steps. One approach is to write an additional wrapper
function that is responsible for converting input objects to the appropriate
types, calling the actual worker function and converting the results back to
a suitable type that can be returned to \proglang{R} (`SEXP`).
Consider the `norm` function below:
```cpp
double norm( double x, double y ) {
return sqrt( x*x + y*y );
}
```
This simple function does not meet the requirements set by the `.Call`
convention, so it cannot be called directly by \proglang{R}. Exposing the
function involves writing a simple wrapper function
that does match the `.Call` requirements. \pkg{Rcpp} makes this easy.
```cpp
using namespace Rcpp;
RcppExport SEXP norm_wrapper(SEXP x_, SEXP y_) {
// step 0: convert input to C++ types
double x = as<double>(x_), y = as<double>(y_);
// step 1: call the underlying C++ function
double res = norm(x, y);
// step 2: return the result as a SEXP
return wrap(res);
}
```
Here we use the (templated) \pkg{Rcpp} converter `as()` which can
transform from a `SEXP` to a number of different \proglang{C++} and
\pkg{Rcpp} types. The \pkg{Rcpp} function `wrap()` offers the opposite
functionality and converts many known types to a `SEXP`.
This process is simple enough, and is used by a number of CRAN packages.
However, it requires direct involvement from the programmer, which quickly
becomes tiresome when many functions are involved. \textsl{Rcpp modules}
provides a much more elegant and unintrusive way to expose \proglang{C++}
functions such as the `norm` function shown above to \proglang{R}.
We should note that \pkg{Rcpp} now has \textsl{Rcpp attributes} which extends
certain aspect of \textsl{Rcpp modules} and makes binding to simple functions
such as this one even easier. With \textsl{Rcpp attributes} we can just write
```cpp
#include <Rcpp.h>
// [[Rcpp::export]]
double norm(double x, double y) {
return sqrt(x*x + y*y);
}
```
See the corresponding vignette \citep{CRAN:Rcpp:Attributes} for details, but
read on for \textsl{Rcpp modules} which provide features not
covered by \textsl{Rcpp attributes}, particularly when it comes to binding
entire \proglang{C++} classes and more.
## Exposing classes using Rcpp
Exposing \proglang{C++} classes or structs is even more of a challenge because it
requires writing glue code for each member function that is to be exposed.
Consider the simple `Uniform` class below:
```cpp
class Uniform {
public:
Uniform(double min_, double max_) :
min(min_), max(max_) {}
NumericVector draw(int n) {
RNGScope scope;
return runif(n, min, max);
}
private:
double min, max;
};
```
To use this class from \proglang{R}, we at least need to expose the constructor and
the `draw` method. External pointers
\citep{R:Extensions} are the perfect vessel for this, and using the
`Rcpp:::XPtr` template from \pkg{Rcpp} we can expose the class
with these two functions:
```cpp
using namespace Rcpp;
/// create external pointer to a Uniform object
RcppExport SEXP Uniform__new(SEXP min_,
SEXP max_) {
// convert inputs to appropriate C++ types
double min = as<double>(min_),
max = as<double>(max_);
// create pointer to an Uniform object and
// wrap it as an external pointer
Rcpp::XPtr<Uniform>
ptr( new Uniform( min, max ), true );
// return the external pointer to the R side
return ptr;
}
/// invoke the draw method
RcppExport SEXP Uniform__draw(SEXP xp, SEXP n_) {
// grab the object as a XPtr (smart pointer)
// to Uniform
Rcpp::XPtr<Uniform> ptr(xp);
// convert the parameter to int
int n = as<int>(n_);
// invoke the function
NumericVector res = ptr->draw( n );
// return the result to R
return res;
}
```
As it is generally a bad idea to expose external pointers `as is',
they usually get wrapped as a slot of an S4 class.
Using `cxxfunction()` from the \pkg{inline} package, we can build this
example on the fly. Suppose the previous example code assigned to a text variable
`unifModCode`, we could then do
<!--
DE 21 Sep 2013: there must a bug somewhere in the vignette processing
as the following example produces only empty lines preceded
by '+' -- same for 0.10.4 release and current 0.10.5 pre-release
hence shortened example to not show code again
-->
```{r, eval=FALSE}
f1 <- cxxfunction( , "", includes = unifModCode,
plugin = "Rcpp" )
getDynLib(f1) ## will display info about 'f1'
```
The following listing shows some \textsl{manual} wrapping to access the code,
we will see later how this can be automated:
```{r, eval=FALSE}
setClass("Uniform",
representation( pointer = "externalptr"))
# helper
Uniform_method <- function(name) {
paste("Uniform", name, sep = "__")
}
# syntactic sugar to allow object$method( ... )
setMethod("$", "Uniform", function(x, name) {
function(...)
.Call(Uniform_method(name) ,
x@pointer, ...)
} )
# syntactic sugar to allow new( "Uniform", ... )
setMethod("initialize", "Uniform",
function(.Object, ...) {
.Object@pointer <-
.Call(Uniform_method("new"), ...)
.Object
} )
u <- new("Uniform", 0, 10)
u$draw( 10L )
```
\pkg{Rcpp} considerably simplifies the code that would
be involved for using external pointers with the traditional \proglang{R} API.
Yet this still involves a lot of mechanical code that quickly
becomes hard to maintain and error prone.
\textsl{Rcpp modules} offer an elegant way to expose the `Uniform`
class in a way that makes both the internal
\proglang{C++} code and the \proglang{R} code easier.
# Rcpp modules
The design of Rcpp modules has been influenced by \proglang{Python} modules which are generated by the
`Boost.Python` library \citep{Abrahams+Grosse-Kunstleve:2003:Boost.Python}.
Rcpp modules provide a convenient and easy-to-use way
to expose \proglang{C++} functions and classes to \proglang{R}, grouped
together in a single entity.
A Rcpp module is created in \proglang{C++} source code using the `RCPP_MODULE`
macro, which then provides declarative code of what the module
exposes to \proglang{R}.
This section provides an extensive description of how Rcpp modules are defined
in standalone \proglang{C++} code and loaded into \proglang{R}. Note however
that defining and using Rcpp modules as part of other \proglang{R} packages
simplifies the way modules are actually loaded, as detailed in Section
\ref{sec:package} below.
## Exposing \proglang{C++} functions using Rcpp modules
Consider the `norm` function from the previous section.
We can expose it to \proglang{R}:
```cpp
using namespace Rcpp;
double norm(double x, double y) {
return sqrt(x*x + y*y);
}
RCPP_MODULE(mod) {
function("norm", &norm);
}
```
The code creates an Rcpp module called `mod`
that exposes the `norm` function. \pkg{Rcpp} automatically
deduces the conversions that are needed for input and output. This alleviates
the need for a wrapper function using either \pkg{Rcpp} or the \proglang{R} API.
On the \proglang{R} side, the module is retrieved by using the
`Module` function from \pkg{Rcpp}
```{r, eval=FALSE}
inc <- '
using namespace Rcpp;
double norm( double x, double y ) {
return sqrt(x*x + y*y);
}
RCPP_MODULE(mod) {
function("norm", &norm);
}
'
fx <- cxxfunction(signature(),
plugin="Rcpp", include=inc)
mod <- Module("mod", getDynLib(fx))
```
Note that this example assumed that the previous code segment defining the
module was returned by the `cxxfunction()` (from the \pkg{inline}
package) as callable \proglang{R} function `fx` from which we can extract the
relevant pointer using `getDynLib()` (again from \pkg{inline}).
Throughout the rest of the examples in this document, we always assume that the
\proglang{C++} code defining a module is used to create an object `fx` via a
similar call to `cxxfunction`. As an alternative, one can also use `sourceCpp`
as described in Section \ref{sec:modules-sourceCpp}.
A module can contain any number of calls to `function` to register
many internal functions to \proglang{R}. For example, these 6 functions:
```{Rcpp yada-fun-def, eval=FALSE}
std::string hello() {
return "hello";
}
int bar( int x) {
return x*2;
}
double foo( int x, double y) {
return x * y;
}
void bla( ) {
Rprintf("hello\\n");
}
void bla1( int x) {
Rprintf("hello (x = %d)\\n", x);
}
void bla2( int x, double y) {
Rprintf("hello (x = %d, y = %5.2f)\\n", x, y);
}
```
can be exposed with the following minimal code:
```{Rcpp yada-fun-module, eval=FALSE}
RCPP_MODULE(yada) {
using namespace Rcpp;
function("hello" , &hello);
function("bar" , &bar );
function("foo" , &foo );
function("bla" , &bla );
function("bla1" , &bla1 );
function("bla2" , &bla2 );
}
```
which can then be used from \proglang{R}:
```{r eval=FALSE}
yada <- Module("yada", getDynLib(fx))
yada$bar(2L)
yada$foo(2L, 10.0)
yada$hello()
yada$bla()
yada$bla1(2L)
yada$bla2(2L, 5.0)
```
The requirements for a function to be exposed to \proglang{R} via Rcpp modules
are:
- The function takes between 0 and 65 parameters.
- The type of each input parameter must be manageable by the `Rcpp::as` template.
- The return type of the function must be either `void` or any type that
can be managed by the `Rcpp::wrap` template.
- The function name itself has to be unique in the module.
In other words, no two functions with
the same name but different signatures are allowed. \proglang{C++} allows overloading
functions. This might be added in future versions of modules.
### Documentation for exposed functions using Rcpp modules
In addition to the name of the function and the function pointer, it is possible
to pass a short description of the function as the third parameter of `function`.
```{Rcpp norm-doc, eval=FALSE}
using namespace Rcpp;
double norm(double x, double y) {
return sqrt(x*x + y*y);
}
RCPP_MODULE(mod) {
function("norm", &norm,
"Provides a simple vector norm");
}
```
The description is used when displaying the function to the \proglang{R} prompt:
```{r, eval=FALSE}
mod <- Module("mod", getDynLib(fx))
show(mod$norm)
```
### Formal arguments specification
`function` also gives the possibility to specify the formal arguments
of the \proglang{R} function that encapsulates the \proglang{C++} function, by passing
a `Rcpp::List` after the function pointer.
```{Rcpp mod_formals, eval=FALSE}
using namespace Rcpp;
double norm(double x, double y) {
return sqrt(x*x + y*y);
}
RCPP_MODULE(mod_formals) {
function("norm",
&norm,
List::create(_["x"] = 0.0,
_["y"] = 0.0),
"Provides a simple vector norm");
}
```
A simple usage example is provided below:
```{r, eval=FALSE}
mod <- Module("mod_formals", getDynLib(fx))
norm <- mod$norm
norm()
norm(x = 2, y = 3)
```
To set formal arguments without default values, omit the rhs.
```{Rcpp mod_formals2, eval=FALSE}
using namespace Rcpp;
double norm(double x, double y) {
return sqrt(x*x + y*y);
}
RCPP_MODULE(mod_formals2) {
function("norm", &norm,
List::create(_["x"], _["y"] = 0.0),
"Provides a simple vector norm");
}
```
This can be used as follows:
```{r, eval=FALSE}
mod <- Module("mod_formals2", getDynLib(fx))
norm <- mod$norm
args(norm)
```
The ellipsis (`...`) can be used to denote that additional arguments
are optional; it does not take a default value.
```{Rcpp mod_formals3, eval=FALSE}
using namespace Rcpp;
double norm(double x, double y) {
return sqrt(x*x + y*y);
}
RCPP_MODULE(mod_formals3) {
function("norm", &norm,
List::create(_["x"], _["..."]),
"documentation for norm");
}
```
This works similarly from the \proglang{R} side where the ellipsis is also understood:
```{r, eval=FALSE}
mod <- Module("mod_formals3", getDynLib(fx))
norm <- mod$norm
args(norm)
```
As of mid-2024, more recent versions of R no longer tolerate 'empty' strings
as placeholders for missing arguments. It is preferable to simply not list
any arguments for functions that take no arguments. Issue #1322 has an example.
## Exposing \proglang{C++} classes using Rcpp modules
Rcpp modules also provide a mechanism for exposing \proglang{C++} classes, based
on the reference classes introduced in \proglang{R} 2.12.0.
### Initial example
A class is exposed using the `class_` keyword. The `Uniform`
class may be exposed to \proglang{R} as follows:
```{Rcpp mod_uniform, eval=FALSE}
using namespace Rcpp;
class Uniform {
public:
Uniform(double min_, double max_) :
min(min_), max(max_) {}
NumericVector draw(int n) const {
RNGScope scope;
return runif(n, min, max);
}
double min, max;
};
double uniformRange(Uniform* w) {
return w->max - w->min;
}
RCPP_MODULE(unif_module) {
class_<Uniform>("Uniform")
.constructor<double,double>()
.field("min", &Uniform::min)
.field("max", &Uniform::max)
.method("draw", &Uniform::draw)
.method("range", &uniformRange)
;
}
```
```{r, eval=FALSE}
unif_module <- Module("unif_module",
getDynLib(fx))
Uniform <- unif_module$Uniform
u <- new(Uniform, 0, 10)
u$draw(10L)
u$range()
u$max <- 1
u$range()
u$draw(10)
```
`class_` is templated by the \proglang{C++} class or struct
that is to be exposed to \proglang{R}.
The parameter of the `class_<Uniform>` constructor is the name we will
use on the \proglang{R} side. It usually makes sense to use the same name as the class
name. While this is not enforced, it might be useful when exposing a class
generated from a template.
Then constructors, fields and methods are exposed.
### Exposing constructors using Rcpp modules
Public constructors that take from 0 and 6 parameters can be exposed
to the \proglang{R} level using the `.constructor` template method of `class_`.
Optionally, `.constructor` can take a description as the first argument.
```cpp
.constructor<double,double>("sets the min and "
"max value of the distribution")
```
Also, the second argument can be a function pointer (called validator)
matching the following type:
```cpp
typedef bool (*ValidConstructor)(SEXP*,int);
```
The validator can be used to implement dispatch to the appropriate constructor,
when multiple constructors taking the same number of arguments are exposed.
The default validator always accepts the constructor as valid if it is passed
the appropriate number of arguments. For example, with the call above, the default
validator accepts any call from \proglang{R} with two `double` arguments (or
arguments that can be cast to `double`).
TODO: include validator example here
### Exposing fields and properties
`class_` has three ways to expose fields and properties, as
illustrated in the example below:
```cpp
using namespace Rcpp;
class Foo {
public:
Foo(double x_, double y_, double z_):
x(x_), y(y_), z(z_) {}
double x;
double y;
double get_z() { return z; }
void set_z(double z_) { z = z_; }
private:
double z;
};
RCPP_MODULE(mod_foo) {
class_<Foo>( "Foo" )
.constructor<double,double,double>()
.field("x", &Foo::x)
.field_readonly("y", &Foo::y)
.property("z", &Foo::get_z, &Foo::set_z)
;
}
```
The `.field` method exposes a public field with read/write access from \proglang{R}.
It accepts an extra parameter to give a short description of the
field:
```cpp
.field("x", &Foo::x, "documentation for x")
```
The `.field_readonly` exposes a public field with read-only access from \proglang{R}.
It also accepts the description of the field.
```cpp
.field_readonly("y", &Foo::y,
"documentation for y")
```
The `.property` method allows indirect access to fields through
a getter and a setter. The setter is optional, and the property is considered
read-only if the setter is not supplied. A description of the property is also
allowed:
```cpp
// with getter and setter
.property("z", &Foo::get_z,
&Foo::set_z, "Documentation for z")
// with only getter
.property("z",
&Foo::get_z, "Documentation for z")
```
The type of the field (\textbf{T}) is deduced from the return type of the getter, and if a
setter is given its unique parameter should be of the same type.
Getters can be member functions taking no parameter and returning a \textbf{T}
(for example `get_z` above), or
a free function taking a pointer to the exposed
class and returning a \textbf{T}, for example:
```cpp
double z_get(Foo* foo) { return foo->get_z(); }
```
Setters can be either a member function taking a \textbf{T} and returning `void`, such
as `set_z` above, or a free function taking a pointer to the target
class and a \textbf{T}:
```cpp
void z_set(Foo* foo, double z) { foo->set_z(z); }
```
Using properties gives more flexibility in case field access has to be tracked
or has impact on other fields. For example, this class keeps track of how many times
the `x` field is read and written.
```{Rcpp mod_bar, eval=FALSE}
class Bar {
public:
Bar(double x_) : x(x_), nread(0), nwrite(0) {}
double get_x() {
nread++;
return x;
}
void set_x(double x_) {
nwrite++;
x = x_;
}
IntegerVector stats() const {
return
IntegerVector::create(_["read"] = nread,
_["write"] = nwrite);
}
private:
double x;
int nread, nwrite;
};
RCPP_MODULE(mod_bar) {
class_<Bar>( "Bar" )
.constructor<double>()
.property( "x", &Bar::get_x, &Bar::set_x )
.method( "stats", &Bar::stats )
;
}
```
Here is a simple usage example:
```{r, eval=FALSE}
mod_bar <- Module("mod_bar", getDynLib(fx))
Bar <- mod_bar$Bar
b <- new(Bar, 10)
b$x + b$x
b$stats()
b$x <- 10
b$stats()
```
### Exposing methods using Rcpp modules
`class_` has several overloaded and templated `.method`
functions allowing the programmer to expose a method associated with the class.
A legitimate method to be exposed by `.method` can be:
- A public member function of the class, either `const` or non-`const`, that
returns `void` or any type that can be handled by `Rcpp::wrap`, and that
takes between 0 and 65 parameters whose types can be handled by `Rcpp::as`.
- A free function that takes a pointer to the target class as its first
parameter, followed by 0 or more (up to 65) parameters that can be handled by
`Rcpp::as` and returning a type that can be handled by `Rcpp::wrap`
or `void`.
### Documenting methods
`.method` can also include a short documentation of the method, after the method
(or free function) pointer.
```cpp
.method("stats", &Bar::stats,
"vector indicating the number of "
"times x has been read and written")
```
TODO: mention overloading, need good example.
### Const and non-const member functions
`.method` is able to expose both `const` and non-`const`
member functions of a class. There are however situations where
a class defines two versions of the same method, differing only in their
signature by the `const`-ness. It is for example the case of the
member functions `back` of the `std::vector` template from
the STL.
```cpp
reference back ( );
const_reference back ( ) const;
```
To resolve the ambiguity, it is possible to use `.const_method`
or `.nonconst_method` instead of `.method` in order
to restrict the candidate methods.
### Special methods
\pkg{Rcpp} considers the methods `[[` and `[[<-` special,
and promotes them to indexing methods on the \proglang{R} side.
### Object finalizers
The `.finalizer` member function of `class_` can be used to
register a finalizer. A finalizer is a free function that takes a pointer
to the target class and return `void`. The finalizer is called
before the destructor and so operates on a valid object of the target class.
It can be used to perform operations, releasing resources, etc ...
The finalizer is called automatically when the \proglang{R} object that encapsulates
the \proglang{C++} object is garbage collected.
### Object factories
The `.factory` member function of `class_` can be used to register a
[factory](https://en.wikipedia.org/wiki/Factory_method_pattern) that
can be used as alternative to a constructor. A factory can be a
static member function or a free function that returns a pointer to
the target class. Typical use-cases include creating objects in a
hierarchy:
```{Rcpp mod_base, eval=FALSE}
#include <Rcpp.h>
using namespace Rcpp;
// abstract class
class Base {
public:
virtual ~Base() {}
virtual std::string name() const = 0;
};
// first derived class
class Derived1: public Base {
public:
Derived1() : Base() {}
virtual std::string name() const {
return "Derived1";
}
};
// second derived class
class Derived2: public Base {
public:
Derived2() : Base() {}
virtual std::string name() const {
return "Derived2";
}
};
Base *newBase( const std::string &name ) {
if (name == "d1"){
return new Derived1;
} else if (name == "d2"){
return new Derived2;
} else {
return 0;
}
}
RCPP_MODULE(mod) {
Rcpp::class_< Base >("Base")
.factory<const std::string&>(newBase)
.method("name", &Base::name);
}
```
The `newBase` method returns a pointer to a `Base` object. Since that
class is an abstract class, the objects are actually instances of
`Derived1` or `Derived2`. The same behavior is now available in \proglang{R}:
```{r, eval=FALSE}
mod <- Module("mod", getDynLib(fx))
Base <- mod$Base
dv1 <- new(Base, "d1")
dv1$name() # returns "Derived1"
dv2 <- new(Base, "d2")
dv2$name() # returns "Derived2"
```
### S4 dispatch
When a \proglang{C++} class is exposed by the `class_` template,
a new S4 class is registered as well. The name of the S4 class is
obfuscated in order to avoid name clashes (i.e. two modules exposing the
same class). This allows implementation of \proglang{R}-level
(S4) dispatch.
For example, consider the \proglang{C++} class `World` exposed in module `yada`:
```{Rcpp yada-world, eval=FALSE}
class World {
public:
World() : msg("hello") {}
void set(std::string msg) { this->msg = msg; }
std::string greet() { return msg; }
private:
std::string msg;
};
RCPP_MODULE(yada){
using namespace Rcpp;
class_<World>("World")
// expose the default constructor
.constructor()
.method("greet", &World::greet)
.method("set", &World::set)
;
}
```
The `show` method for `World` objects is then implemented as:
```{r, eval=FALSE}
yada <- Module("yada", getDynLib(fx))
setMethod("show", yada$World , function(object) {
msg <- paste("World object with message : ",
object$greet())
writeLines(msg)
} )
yada$World$new() # implictly calls show
```
TODO: mention R inheritance (John ?)
### Extending `Rcpp::as` and `Rcpp::wrap`
Sometimes it is necessary to extend `Rcpp::as` or `Rcpp::wrap` for
classes that are also exposed using Rcpp modules. Instead of using the
general methods described in the _Rcpp Extending_ vignette, one can
use the `RCPP_EXPOSED_AS` or `RCPP_EXPOSED_WRAP` macros.
Alternatively the `RCPP_EXPOSED_CLASS` macro defines both `Rcpp::as`
and `Rcpp::wrap` specializations. Do not use these macros together
with the generic extension mechanisms. Note that opposed to the
generic methods, these macros can be used _after_ `Rcpp.h` has been
loaded. Here an example of a pair of Rcpp modules exposed classes
where one of them has a method taking an instance of the other class
as argument. In this case it is sufficient to use `RCPP_EXPOSED_AS` to
enable the transparent conversion from \proglang{R} to \proglang{C++}:
```{Rcpp exposed_as, eval=FALSE}
#include <Rcpp.h>
class Foo {
public:
Foo() = default;
};
class Bar {
public:
Bar() = default;
void handleFoo(Foo foo) {
Rcpp::Rcout << "Got a Foo!" << std::endl;
};
};
RCPP_EXPOSED_AS(Foo)
RCPP_MODULE(Foo){
Rcpp::class_<Foo>("Foo")
.constructor();
}