r-lib / cpp11 Goto Github PK
View Code? Open in Web Editor NEWcpp11 helps you to interact with R objects using C++ code.
Home Page: https://cpp11.r-lib.org/
License: Other
cpp11 helps you to interact with R objects using C++ code.
Home Page: https://cpp11.r-lib.org/
License: Other
Prefix them all with cpp_()
, e.g. cpp_source()
, cpp_eval()
, cpp_vendor()
.
Should the code generator support having default arguments? I am not sure, it would only work for numeric (and boolean) values and would add complexity to the generation code.
But maybe it is worth it.
Using iterators are great for abstraction away some of the boilerplate as outlined in https://cpp11.r-lib.org/articles/cpp11.html#using-iterators.
Is it possible to use the same framework to perform calculations in a row-wise fashion for a matrix?
Is there an equivalent to // [[Rcpp::depends()]] for cpp11? Trying to make a MRE (so not in a package) and need to link with another package for that one bit of code.
What correct way to return NA_character
?
> cpp_eval('cpp11::r_string(NA_STRING)')
[1] "NA"
> cpp_eval('cpp11::writable::strings(NA_STRING)')
[1] NA
> cpp_eval('cpp11::writable::strings({NA_STRING})')
[1] "NA"
> cpp_eval('cpp11::writable::strings({NA_STRING, "text"})')
[1] "NA" "text"
cpp11::cpp_function('
cpp11::writable::logicals bools(){
cpp11::writable::logicals x(1);
x[0] = true;
return x;
}
', quiet = FALSE)
#> clang++ -mmacosx-version-min=10.13 -std=gnu++11 -I"/Library/Frameworks/R.framework/Resources/include" -DNDEBUG -I/Users/romainfrancois/.R/library/4.0/cpp11/include -I/usr/local/include -fPIC -Wall -O3 -Wall -Wimplicit-int-float-conversion -c /private/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T/Rtmp4AL6sg/file3d916be862b1/src/code_0.cpp -o /private/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T/Rtmp4AL6sg/file3d916be862b1/src/code_0.o
#> /private/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T/Rtmp4AL6sg/file3d916be862b1/src/code_0.cpp:8:8: error: no viable overloaded '='
#> x[0] = true;
#> ~~~~ ^ ~~~~
#> /Users/romainfrancois/.R/library/4.0/cpp11/include/cpp11/r_vector.hpp:216:9: note: candidate function (the implicit copy assignment operator) not viable: no known conversion from 'bool' to 'const cpp11::writable::r_vector<Rboolean>::proxy' for 1st argument
#> class proxy {
#> ^
#> /Users/romainfrancois/.R/library/4.0/cpp11/include/cpp11/logicals.hpp:51:71: note: candidate function not viable: no known conversion from 'bool' to 'const Rboolean' for 1st argument
#> inline typename r_vector<Rboolean>::proxy& r_vector<Rboolean>::proxy::operator=(
#> ^
#> 1 error generated.
#> make: *** [/private/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T/Rtmp4AL6sg/file3d916be862b1/src/code_0.o] Error 1
#> Error in dyn.load(shared_lib, local = TRUE, now = TRUE): unable to load shared object '/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T//Rtmp4AL6sg/file3d916be862b1/src/code_0.so':
#> dlopen(/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T//Rtmp4AL6sg/file3d916be862b1/src/code_0.so, 6): image not found
bools()
#> Error in .Call("_code_0_bools", PACKAGE = "code_0"): "_code_0_bools" not available for .Call() for package "code_0"
Created on 2020-07-24 by the reprex package (v0.3.0.9001)
We can do this 👇, but I believe it still would be useful to allow it.
cpp11::cpp_function('
cpp11::writable::logicals bools(){
cpp11::writable::logicals x(1);
x[0] = true ? TRUE : FALSE;
return x;
}
', quiet = FALSE)
#> clang++ -mmacosx-version-min=10.13 -std=gnu++11 -I"/Library/Frameworks/R.framework/Resources/include" -DNDEBUG -I/Users/romainfrancois/.R/library/4.0/cpp11/include -I/usr/local/include -fPIC -Wall -O3 -Wall -Wimplicit-int-float-conversion -c /private/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T/RtmpFsTE6w/file3dd0596b29c2/src/code_0.cpp -o /private/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T/RtmpFsTE6w/file3dd0596b29c2/src/code_0.o
#> clang++ -mmacosx-version-min=10.13 -std=gnu++11 -I"/Library/Frameworks/R.framework/Resources/include" -DNDEBUG -I/Users/romainfrancois/.R/library/4.0/cpp11/include -I/usr/local/include -fPIC -Wall -O3 -Wall -Wimplicit-int-float-conversion -c /private/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T/RtmpFsTE6w/file3dd0596b29c2/src/cpp11.cpp -o /private/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T/RtmpFsTE6w/file3dd0596b29c2/src/cpp11.o
#> clang++ -mmacosx-version-min=10.13 -std=gnu++11 -dynamiclib -Wl,-headerpad_max_install_names -undefined dynamic_lookup -single_module -multiply_defined suppress -L/Library/Frameworks/R.framework/Resources/lib -L/usr/local/lib -o /private/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T/RtmpFsTE6w/file3dd0596b29c2/src/code_0.so /private/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T/RtmpFsTE6w/file3dd0596b29c2/src/code_0.o /private/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T/RtmpFsTE6w/file3dd0596b29c2/src/cpp11.o -F/Library/Frameworks/R.framework/.. -framework R -Wl,-framework -Wl,CoreFoundation
bools()
#> [1] TRUE
Created on 2020-07-24 by the reprex package (v0.3.0.9001)
Hi,
I am doing a minimal hello world example of using cpp11 in an R package. When I run your example code:
#include <map>
#include "cpp11.hpp"
using namespace cpp11;
[[cpp11::register]]
SEXP table_cpp(doubles x) {
std::map<double, int> counts;
int n = x.size();
for (int i = 0; i < n; i++) {
counts[x[i]]++;
}
return as_sexp(counts);
}
I get the below output. I'm still learning C++, so I'm not 100% sure if this is intended behavior, but I think not.
> cpp11::cpp_register()
> devtools::document()
Updating testcpp11 documentation
Loading testcpp11
Re-compiling testcpp11
─ installing *source* package ‘testcpp11’ ...
** using staged installation
** libs
ccache g++-10 -std=gnu++11 -I"/usr/share/R/include" -DNDEBUG -I"/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include" -fpic -g -O2 -fdebug-prefix-map=/build/r-base-V28x5H/r-base-3.6.3=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -g -c helloCpp.cpp -o helloCpp.o
helloCpp.cpp: In function ‘SEXPREC* table_cpp(cpp11::doubles)’:
helloCpp.cpp:74:24: error: no matching function for call to ‘as_sexp(std::map<double, int>&)’
74 | return as_sexp(counts);
| ^
In file included from /home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11.hpp:5,
from helloCpp.cpp:2:
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:144:13: note: candidate: ‘template<class T, cpp11::is_integral<T>* <anonymous> > SEXPREC* cpp11::as_sexp(T)’
144 | inline SEXP as_sexp(T from) {
| ^~~~~~~
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:144:13: note: template argument deduction/substitution failed:
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp: In substitution of ‘template<class T> using is_integral = typename std::enable_if<((std::is_integral<_Tp>::value && (! std::is_same<typename std::decay<_Tp>::type, bool>::value)) && (! std::is_same<typename std::decay<_Tp>::type, char>::value)), typename std::decay<_Tp>::type>::type [with T = std::map<double, int>]’:
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:143:41: required from here
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:25:7: error: no type named ‘type’ in ‘struct std::enable_if<false, std::map<double, int> >’
25 | using is_integral = typename std::enable_if<
| ^~~~~~~~~~~
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:149:13: note: candidate: ‘template<class T, cpp11::is_floating_point_value<T>* <anonymous> > SEXPREC* cpp11::as_sexp(T)’
149 | inline SEXP as_sexp(T from) {
| ^~~~~~~
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:149:13: note: template argument deduction/substitution failed:
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp: In subs /home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp: In substitution of ‘template<class T> using is_floating_point_value = typename std::enable_if<std::is_floating_point<_Tp>::value, T>::type [with T = std::map<double, int>]’:
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:148:53: required from here
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:83:7: error: no type named ‘type’ in ‘struct std::enable_if<false, std::map<double, int> >’
83 | using is_floating_point_value =
| ^~~~~~~~~~~~~~~~~~~~~~~
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:153:13: note: candidate: ‘SEXPREC* cpp11::as_sexp(const string&)’
153 | inline SEXP as_sexp(const std::string& from) {
| ^~~~~~~
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:153:40: note: no known conversion for argument 1 from ‘std::map<double, int>’ to ‘const string&’ {aka ‘const std::__cxx11::basic_string<char>&’}
153 | inline SEXP as_sexp(const std::string& from) {
| ~~~~~~~~~~~~~~~~~~~^~~~
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:165:13: note: candidate: ‘template<class T, typename std::enable_if<std::is_same<typename std::decay<_Tp>::type, bool>::value, typename std::decay<_Tp>::type>::type <anonymous> > SEXPREC* cpp11::as_sexp(T)’
165 | inline SEXP as_sexp(T from) {
| ^~~~~~~
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:165:13: note: template argument deduction/substitution failed:
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:164:36: error: no type named ‘type’ in ‘struct std::enable_if<false, std::map<double, int> >’
164 | template <typename T, is_bool<T> = false>
| ^~~~~
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:172:13: note: candidate: ‘template<class C, class T, typename std::enable_if<(! std::is_convertible<C, SEXPREC*>::value), typename std::enable_if<((std::is_integral<_Si /home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:172:13: note: candidate: ‘template<class C, class T, typename std::enable_if<(! std::is_convertible<C, SEXPREC*>::value), typename std::enable_if<((std::is_integral<_Size>::value && (! std::is_same<typename std::decay<_Tp2>::type, bool>::value)) && (! std::is_same<typename std::decay<_Tp2>::type, char>::value)), typename std::decay<_Tp2>::type>::type>::type* <anonymous> > SEXPREC* cpp11::as_sexp(C)’
172 | inline SEXP as_sexp(C from) {
| ^~~~~~~
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:172:13: note: template argument deduction/substitution failed:
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:171:60: error: no type named ‘type’ in ‘struct std::enable_if<false, std::pair<const double, int> >’
171 | is_integral<T>>::type* = nullptr>
| ^~~~~~~
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:184:13: note: candidate: ‘SEXPREC* cpp11::as_sexp(std::initializer_list<int>)’
184 | inline SEXP as_sexp(std::initializer_list<int> from) {
| ^~~~~~~
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:184:48: note: no known conversion for argument 1 from ‘std::map<double, int>’ to ‘std::initializer_list<int>’
184 | inline SEXP as_sexp(std::initializer_list<int> from) {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:190:13: note: candidate: ‘template<class C, class T, cpp11::is_floating_point_value<T>* <anonymous> > SEXPREC* cpp11::as_sexp(C)’
190 | inline SEXP as_sexp(C from) {
| ^~~~~~~
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:190:13: note: template argument deduction/substitution failed:
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp: In substitution of ‘template<class T> using is_floating_point_value = typename std::enable_if<std::is_floating_point<_Tp>::value, T>::type [with T = std::pair<const double, int>]’:
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:189:41: required from here
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:83:7: error: no type named ‘type’ in ‘struct std::enable_if<false, std::pair<const double, int> >’
83 | using is_floating_point_value =
| ^~~~~~~~~~~~~~~~~~~~~~~
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:202:13: note: candidate: ‘SEXPREC* cpp11::as_sexp(std::initializer_list<double>)’
202 | inline SEXP as_sexp(std::initializer_list<double> from) {
| ^~~~~~~
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:202:51: note: no known conversion for argument 1 from ‘std::map<double, int>’ to ‘std::initializer_list<double>’
202 | inline SEXP as_sexp(std::initializer_list<double> from) {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:207:13: note: candidate: ‘template<class C, class T, cpp11::is_bool<T>* <anonymous> > SEXPREC* cpp11::as_sexp(C)’
207 | inline SEXP as_sexp(C from) {
| ^~~~~~~
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:207:13: note: template argument deduction/substitution failed:
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp: In substitution of ‘template<class T> using is_bool = typename std::enable_if<std::is_same<typename std::decay<_Tp>::type, bool>::value, typename std::decay<_Tp>::type>::type [with T = std::pair<const double, int>]’:
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:206:74: required from here
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:160:7: error: no type named ‘type’ in ‘struct std::enable_if<false, std::pair<const double, int> >’
160 | using is_bool =
| ^~~~~~~
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:219:13: /home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:219:13: note: candidate: ‘SEXPREC* cpp11::as_sexp(std::initializer_list<bool>)’
219 | inline SEXP as_sexp(std::initializer_list<bool> from) {
| ^~~~~~~
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:219:49: note: no known conversion for argument 1 from ‘std::map<double, int>’ to ‘std::initializer_list<bool>’
219 | inline SEXP as_sexp(std::initializer_list<bool> from) {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:231:13: note: candidate: ‘template<class C, class T, cpp11::is_convertible_to_std_string<T>* <anonymous> > SEXPREC* cpp11::as_sexp(C)’
231 | inline SEXP as_sexp(C from) {
| ^~~~~~~
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:231:13: note: template argument deduction/substitution failed:
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp: In substitution of ‘template<class T> using is_convertible_to_std_string = typename std::enable_if<(std::is_convertible<typename std::decay<_Tp>::type, std::__cxx11::basic_string<char> >::value && (! std::is_convertible<typename std::decay<_Tp>::type, const char*>::value)), typename std::decay<_Tp>::type>::type [with T = std::pair<const double, int>]’:
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:230:46: required from here
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:224:7: error: no type named ‘type’ in ‘struct std::enable_if<false, std::pair<const double, int> >’
224 | using is_convertible_to_std_string = typename std::enable_if<
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:259:13: note: candidate: ‘template<class C, class T, cpp11::is_convertible_to_const_char<T>* <anonymous> > SEXPREC* cpp11::as_sexp(C)’
259 | inline SEXP as_sexp(C from) {
| ^~~~~~~
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:259:13: note: template argument deduction/substitution failed:
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp: In substitution of ‘template<class T> using is_convertible_to_const_char = typename std::enable_if<(std::is_convertible<typename std::decay<_Tp>::type, const char*>::value && (! std::is_convertible<typename std::decay<_Tp>::type, SEXPREC*>::value)), typename std::decay<_Tp>::type>::type [with T = std::pair<const double, int>]’:
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:258:46: required from here
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:252:7: error: no type named ‘type’ in ‘struct std::enable_if<false, std::pair<const double, int> >’
252 | using is_convertible_to_const_char = typename std::enable_if<
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:279:13: note: candidate: ‘SEXPREC* cpp11::as_sexp(std::initializer_list<const char*>)’
279 | inline SEXP as_sexp(std::initializer_list<const char*> from) {
| ^~~~~~~
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:279:56: note: no known conversion for argument 1 from ‘std::map<double, int>’ to ‘std::initializer_list<const char*>’
279 | inline SEXP as_sexp(std::initializer_list<const char*> from) {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:283:13: note: candidate: ‘SEXPREC* cpp11::as_sexp(SEXP)’
283 | inline SEXP as_sexp(SEXP from) { return from; }
| ^~~~~~~
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/as.hpp:283:26: note: no known conversion for argument 1 from ‘std::map<double, int>’ to ‘SEXP’ {aka ‘SEXPREC*’}
283 | inline SEXP as_sexp(SEXP from) { return from; }
| ~~~~~^~~~
In file included from /home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/list.hpp:8,
from /home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/data_frame.hpp:10,
from /home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11.hpp:7,
from helloCpp.cpp:2:
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/r_string.hpp:58:13: note: candidate: ‘template<class T, cpp11::is_convertible_to_cpp11_string<T>* <anonymous> > SEXPREC* cpp11::as_sexp(T)’
58 | inline SEXP as_sexp(T from) {
| ^~~~~~~
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/r_string.hpp:58:13: note: template argument deduction/substitution failed:
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/r_string.hpp: In substitution of ‘template<class T> using is_convertible_to_cpp11_string = typename std::enable_if<(std::is_convertible<T, cpp11::r_string>::value && (! std::is_convertible<T, const char*>::value)), T>::type [with T = std::map<double, int>]’:
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/r_string.hpp:57:60: required from here
/home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/r_string.hpp:52:7: error: no type named ‘type’ in ‘struct std::enable_if<false, std::map<double, int> >’
52 | using is_convertible_to_cpp11_string =
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/lib/R/etc/Makeconf:177: recipe for target 'helloCpp.o' failed
make: *** [helloCpp.o] Error 1
ERROR: compilation failed for package ‘testcpp11’
─ removing ‘/tmp/Rtmp6dP72C/devtools_install_1f3d6b99a0e5/testcpp11’
Error in (function (command = NULL, args = character(), error_on_status = TRUE, :
System command 'R' failed, exit status: 1, stdout + stderr (last 10 lines):
E> /home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/r_string.hpp:58:13: note: template argument deduction/substitution failed:
E> /home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/r_string.hpp: In substitution of ‘template<class T> using is_convertible_to_cpp11_string = typename std::enable_if<(std::is_convertible<T, cpp11::r_string>::value && (! std::is_convertible<T, const char*>::value)), T>::type [with T = std::map<double, int>]’:
E> /home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/r_string.hpp:57:60: required from here
E> /home/mads/R/x86_64-pc-linux-gnu-library/3.6/cpp11/include/cpp11/r_string.hpp:52:7: error: no type named ‘type’ in ‘struct std::enable_if<false, std::map<double, int> >’
E> 52 | using is_convertible_to_cpp11_string =
E> | ^~~~~~~~~~~~~~~~~~~~~~~~
[...]
> sessionInfo()
R version 3.6.3 (2020-02-29)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 18.04.4 LTS
Matrix products: default
BLAS: /usr/lib/x86_64-linux-gnu/blas/libblas.so.3.7.1
LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.7.1
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
library(cpp11)
x <- matrix(runif(4), nrow = 2)
cpp_function("int get_nrow(cpp11::doubles_matrix x) {
int res = x.nrow();
return(res);
}")
get_nrow(x)
#> [1] 2076180480
cpp_function("int get_ncol(cpp11::doubles_matrix x) {
int res = x.ncol();
return(res);
}")
get_ncol(x)
#> [1] 0
Created on 2020-06-16 by the reprex package (v0.3.0)
What's the motivation for starting at C++11 now that C++17 (and goodies like if constexpr
) is available on all platforms?
Not entirely sure if it should return R_NilValue
or an empty character vector, probably the latter.
Something like this should reproduce it.
cpp11::writable::doubles x;
x.names()
Names matching /is_\w+/
are conventionally reserved for bool_constant
s, but in cpp11 they connote a typedef of enable_if
, for example (as.hpp:24):
template <typename T>
using is_integral = typename std::enable_if<
std::is_integral<T>::value &&
!std::is_same<typename std::decay<T>::type, bool>::value &&
!std::is_same<typename std::decay<T>::type, char>::value,
typename std::decay<T>::type>::type;
The prefix enable_if_
will make it clearer to newcomers that this is an SFINAE helper.
Which lets you create and modify an environment.
cc @thomasp85
At the moment, coersion from an R numeric scalar to an int
works nicely - doubles are converted to integers if they are representable as integers without truncation of the decimal part. However, the same is not true of a vector of numeric values into cpp11::integers
:
cpp11::cpp_source(
code = c(
"#include <cpp11.hpp>",
"[[cpp11::register]]",
"void test(int x, cpp11::integers y) {",
"}"))
test(1L, 1L) # works, as expected
test(1, 1L) # works, due to the double -> int conversion
test(1L, 1) # fails with error "Invalid input type, expected 'integer' actual 'double'"
The same problem impacts passing a vector of integers to a function expecting doubles:
cpp11::cpp_source(
code = c(
"#include <cpp11.hpp>",
"[[cpp11::register]]",
"void test2(cpp11::doubles y) {",
"}"))
test2(seq_len(4))
#> Error in test2(seq_len(4)) :
#> Invalid input type, expected 'double' actual 'integer'
It would be nice if it is possible to relax this as practically this requires additional wrappers to the be added in either the C++ or the R code, especially as the name of the problematic variable can't be easily found from the error message.
First, thanks for this package! I've longed for a lean R to C++ interface for quite awhile.
It looks like the END_CPP11 macro lacks a catch-all exception handler. I was using a Boost library and wondering why I was getting aborts (it was not using std::exception). Was a catch(...){}
block intentionally omitted?
cpp11::cpp_function('void test() { throw; }')
test() # abort
On OSX
R version 3.6.3 (2020-02-29) -- "Holding the Windsock"
Copyright (C) 2020 The R Foundation for Statistical Computing
Platform: x86_64-apple-darwin15.6.0 (64-bit)
R is free software and comes with ABSOLUTELY NO WARRANTY.
You are welcome to redistribute it under certain conditions.
Type 'license()' or 'licence()' for distribution details.
Natural language support but running in an English locale
R is a collaborative project with many contributors.
Type 'contributors()' for more information and
'citation()' on how to cite R or R packages in publications.
Type 'demo()' for some demos, 'help()' for on-line help, or
'help.start()' for an HTML browser interface to help.
Type 'q()' to quit R.
> cpp11::cpp_function('void test() { throw; }')
> test() # abort
libc++abi.dylib: terminating
zsh: abort R
Hi,
I'm trying to install another package (tidyr) on CentOS7 which is apparently trying to use cpp11 library.
It throws multiple errors:
g++ -std=gnu++11 -I"/software/R-3.6.2/include" -DNDEBUG -I"/data/software/R-3.6.2/library/cpp11/include" -I/usr/include -I/software/CLAPACK-3.2.1/INCLUDE -I/software/gsl-2.6/include -I/software/proj-6.0.0/include/proj -I/software/hdf5-1.10.4/include/ -fpic -g -O2 -c cpp11.cpp -o cpp11.o
In file included from /data/software/R-3.6.2/library/cpp11/include/cpp11/as.hpp:8:0,
from /data/software/R-3.6.2/library/cpp11/include/cpp11.hpp:5,
from /data/software/R-3.6.2/library/cpp11/include/cpp11/declarations.hpp:8,
from cpp11.cpp:4:
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp: In lambda function:
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:183:47: error: parameter packs not expanded with ‘...’:
return unwind_protect([&] { return ptr_(a...); });
^
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:183:47: note: ‘a’
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:183:48: error: expansion pattern ‘a’ contains no argument packs
return unwind_protect([&] { return ptr_(a...); });
^
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp: In lambda function:
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:199:38: error: parameter packs not expanded with ‘...’:
unwind_protect([&] { Rf_error(fmt, args...); });
^
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:199:38: note: ‘args’
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:199:42: error: expansion pattern ‘args’ contains no argument packs
unwind_protect([&] { Rf_error(fmt, args...); });
^
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp: In lambda function:
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:206:46: error: parameter packs not expanded with ‘...’:
unwind_protect([&] { Rf_error(fmt.c_str(), args...); });
^
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:206:46: note: ‘args’
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:206:50: error: expansion pattern ‘args’ contains no argument packs
unwind_protect([&] { Rf_error(fmt.c_str(), args...); });
^
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp: In instantiation of ‘struct cpp11::protect::function<F>::operator()(A ...) const [with A = {}; F = void(); decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) = void]::__lambda2’:
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:183:55: required from ‘decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) cpp11::protect::function<F>::operator()(A ...) const [with A = {}; F = void(); decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) = void]’
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:195:65: required from here
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:183:47: error: using invalid field ‘cpp11::protect::function<F>::operator()(A ...) const::__lambda2::__a’
return unwind_protect([&] { return ptr_(a...); });
^
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp: In instantiation of ‘decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) cpp11::protect::function<F>::operator()(A ...) const [with A = {}; F = void(); decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) = void]’:
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:195:65: required from here
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:183:55: error: return-statement with a value, in function returning 'void' [-fpermissive]
return unwind_protect([&] { return ptr_(a...); });
^
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp: In instantiation of ‘struct cpp11::protect::function<F>::operator()(A ...) const [with A = {const char*, cetype_t}; F = SEXPREC*(const char*, cetype_t); decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) = SEXPREC*]::__lambda2’:
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:183:55: required from ‘decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) cpp11::protect::function<F>::operator()(A ...) const [with A = {const char*, cetype_t}; F = SEXPREC*(const char*, cetype_t); decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) = SEXPREC*]’
/data/software/R-3.6.2/library/cpp11/include/cpp11/r_string.hpp:16:69: required from here
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:183:47: error: using invalid field ‘cpp11::protect::function<F>::operator()(A ...) const::__lambda2::__a’
return unwind_protect([&] { return ptr_(a...); });
^
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp: In instantiation of ‘struct cpp11::protect::function<F>::operator()(A ...) const [with A = {int, long unsigned int}; F = SEXPREC*(unsigned int, long int); decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) = SEXPREC*]::__lambda2’:
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:183:55: required from ‘decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) cpp11::protect::function<F>::operator()(A ...) const [with A = {int, long unsigned int}; F = SEXPREC*(unsigned int, long int); decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) = SEXPREC*]’
/data/software/R-3.6.2/library/cpp11/include/cpp11/list.hpp:75:67: required from here
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:183:47: error: using invalid field ‘cpp11::protect::function<F>::operator()(A ...) const::__lambda2::__a’
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp: In instantiation of ‘struct cpp11::protect::function<F>::operator()(A ...) const [with A = {int, long int}; F = SEXPREC*(unsigned int, long int); decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) = SEXPREC*]::__lambda2’:
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:183:55: required from ‘decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) cpp11::protect::function<F>::operator()(A ...) const [with A = {int, long int}; F = SEXPREC*(unsigned int, long int); decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) = SEXPREC*]’
/data/software/R-3.6.2/library/cpp11/include/cpp11/list.hpp:107:74: required from here
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:183:47: error: using invalid field ‘cpp11::protect::function<F>::operator()(A ...) const::__lambda2::__a’
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp: In instantiation of ‘struct cpp11::protect::function<F>::operator()(A ...) const [with A = {SEXPREC*, long int}; F = SEXPREC*(SEXPREC*, long int); decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) = SEXPREC*]::__lambda2’:
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:183:55: required from ‘decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) cpp11::protect::function<F>::operator()(A ...) const [with A = {SEXPREC*, long int}; F = SEXPREC*(SEXPREC*, long int); decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) = SEXPREC*]’
/data/software/R-3.6.2/library/cpp11/include/cpp11/list.hpp:108:73: required from here
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:183:47: error: using invalid field ‘cpp11::protect::function<F>::operator()(A ...) const::__lambda2::__a’
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp: In instantiation of ‘struct cpp11::protect::function<F>::operator()(A ...) const [with A = {const char*}; F = SEXPREC*(const char*); decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) = SEXPREC*]::__lambda2’:
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:183:55: required from ‘decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) cpp11::protect::function<F>::operator()(A ...) const [with A = {const char*}; F = SEXPREC*(const char*); decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) = SEXPREC*]’
/data/software/R-3.6.2/library/cpp11/include/cpp11/function.hpp:59:50: required from here
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:183:47: error: using invalid field ‘cpp11::protect::function<F>::operator()(A ...) const::__lambda2::__a’
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp: In instantiation of ‘struct cpp11::protect::function<F>::operator()(A ...) const [with A = {SEXPREC*, SEXPREC*}; F = SEXPREC*(SEXPREC*, SEXPREC*); decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) = SEXPREC*]::__lambda2’:
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:183:55: required from ‘decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) cpp11::protect::function<F>::operator()(A ...) const [with A = {SEXPREC*, SEXPREC*}; F = SEXPREC*(SEXPREC*, SEXPREC*); decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) = SEXPREC*]’
/data/software/R-3.6.2/library/cpp11/include/cpp11/function.hpp:59:58: required from here
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:183:47: error: using invalid field ‘cpp11::protect::function<F>::operator()(A ...) const::__lambda2::__a’
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp: In instantiation of ‘struct cpp11::protect::function<F>::operator()(A ...) const [with A = {SEXPREC*, cpp11::sexp}; F = SEXPREC*(SEXPREC*, SEXPREC*); decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) = SEXPREC*]::__lambda2’:
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:183:55: required from ‘decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) cpp11::protect::function<F>::operator()(A ...) const [with A = {SEXPREC*, cpp11::sexp}; F = SEXPREC*(SEXPREC*, SEXPREC*); decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) = SEXPREC*]’
/data/software/R-3.6.2/library/cpp11/include/cpp11/function.hpp:69:66: required from here
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:183:47: error: using invalid field ‘cpp11::protect::function<F>::operator()(A ...) const::__lambda2::__a’
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp: In instantiation of ‘struct cpp11::protect::function<F>::operator()(A ...) const [with A = {SEXPREC*, SEXPREC*, Rboolean}; F = SEXPREC*(SEXPREC*, SEXPREC*, Rboolean); decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) = SEXPREC*]::__lambda2’:
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:183:55: required from ‘decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) cpp11::protect::function<F>::operator()(A ...) const [with A = {SEXPREC*, SEXPREC*, Rboolean}; F = SEXPREC*(SEXPREC*, SEXPREC*, Rboolean); decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) = SEXPREC*]’
/data/software/R-3.6.2/library/cpp11/include/cpp11/environment.hpp:36:81: required from here
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:183:47: error: using invalid field ‘cpp11::protect::function<F>::operator()(A ...) const::__lambda2::__a’
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp: In instantiation of ‘struct cpp11::protect::function<F>::operator()(A ...) const [with A = {cpp11::sexp, SEXPREC*, Rboolean}; F = SEXPREC*(SEXPREC*, SEXPREC*, Rboolean); decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) = SEXPREC*]::__lambda2’:
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:183:55: required from ‘decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) cpp11::protect::function<F>::operator()(A ...) const [with A = {cpp11::sexp, SEXPREC*, Rboolean}; F = SEXPREC*(SEXPREC*, SEXPREC*, Rboolean); decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) = SEXPREC*]’
/data/software/R-3.6.2/library/cpp11/include/cpp11/environment.hpp:47:58: required from here
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:183:47: error: using invalid field ‘cpp11::protect::function<F>::operator()(A ...) const::__lambda2::__a’
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp: In instantiation of ‘struct cpp11::protect::function<F>::operator()(A ...) const [with A = {int, int}; F = SEXPREC*(unsigned int, long int); decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) = SEXPREC*]::__lambda2’:
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:183:55: required from ‘decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) cpp11::protect::function<F>::operator()(A ...) const [with A = {int, int}; F = SEXPREC*(unsigned int, long int); decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) = SEXPREC*]’
/data/software/R-3.6.2/library/cpp11/include/cpp11/strings.hpp:71:70: required from here
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:183:47: error: using invalid field ‘cpp11::protect::function<F>::operator()(A ...) const::__lambda2::__a’
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp: In instantiation of ‘struct cpp11::protect::function<F>::operator()(A ...) const [with A = {SEXPREC*}; F = SEXPREC*(SEXPREC*); decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) = SEXPREC*]::__lambda2’:
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:183:55: required from ‘decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) cpp11::protect::function<F>::operator()(A ...) const [with A = {SEXPREC*}; F = SEXPREC*(SEXPREC*); decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) = SEXPREC*]’
/data/software/R-3.6.2/library/cpp11/include/cpp11/strings.hpp:73:45: required from here
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:183:47: error: using invalid field ‘cpp11::protect::function<F>::operator()(A ...) const::__lambda2::__a’
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp: In instantiation of ‘struct cpp11::protect::function<F>::operator()(A ...) const [with A = {cpp11::sexp, SEXPREC*}; F = SEXPREC*(SEXPREC*, SEXPREC*); decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) = SEXPREC*]::__lambda2’:
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:183:55: required from ‘decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) cpp11::protect::function<F>::operator()(A ...) const [with A = {cpp11::sexp, SEXPREC*}; F = SEXPREC*(SEXPREC*, SEXPREC*); decltype (declval<F*>()(cpp11::protect::function::operator()::a ...)) = SEXPREC*]’
/data/software/R-3.6.2/library/cpp11/include/cpp11/function.hpp:27:43: required from ‘cpp11::sexp cpp11::function::operator()(Args&& ...) const [with Args = {SEXPREC*&, cpp11::named_arg&}]’
/data/software/R-3.6.2/library/cpp11/include/cpp11/environment.hpp:60:35: required from here
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:183:47: error: using invalid field ‘cpp11::protect::function<F>::operator()(A ...) const::__lambda2::__a’
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp: In instantiation of ‘struct cpp11::stop(const char*, Args ...) [with Args = {}]::__lambda3’:
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:199:49: required from ‘void cpp11::stop(const char*, Args ...) [with Args = {}]’
/data/software/R-3.6.2/library/cpp11/include/cpp11/as.hpp:98:39: required from ‘cpp11::is_logical<T> cpp11::as_cpp(SEXP) [with T = bool; cpp11::is_logical<T> = bool; SEXP = SEXPREC*]’
cpp11.cpp:24:452: required from here
/data/software/R-3.6.2/library/cpp11/include/cpp11/protect.hpp:199:38: error: using invalid field ‘cpp11::stop(const char*, Args ...)::__lambda3::__args’
unwind_protect([&] { Rf_error(fmt, args...); });
^
make: *** [cpp11.o] Error 1
ERROR: compilation failed for package ‘tidyr’
Apparently the compilation errors are coming from several hpp files.
If you have any idea of a simple flag to add to make it work? Or if I need to recompile the cpp11 library with specific flags.
Thanks in advance
to avoid ambiguities when using sizes from std::vector containers.
Any thoughts on ensuring the correct RNG functionality with the Rmath
library?
For instance, if we create a cpp11
function that interfaces with Rf_norm()
:
cpp11::cpp_source(
code = '
#include "cpp11/doubles.hpp"
#include "R.h"
#include "Rmath.h"
[[cpp11::register]]
double rng_cpp() {
double x = Rf_rnorm(0, 1);
return x;
}
[[cpp11::register]]
double rng_explicit_state_cpp() {
GetRNGstate();
double x = Rf_rnorm(0, 1);
PutRNGstate();
return x;
}', quiet = FALSE)
The subsequent running of the versions between C++ and R produce the same result without a seed being re-set.
set.seed(3161611)
rng_cpp()
#> [1] -0.9325398
rnorm(1)
#> [1] -0.9325398
Under the second function with an explicit Get/Put state call the desired results are achieved:
set.seed(3161611)
rng_explicit_state_cpp()
#> [1] -0.9325398
rnorm(1)
#> [1] 0.8282708
From looking at exported code it seems like there is no wrapping of C++ calls with GetRNGstate()
/PutRNGstate()
. Perhaps this should be added to the converting documents or addressed during code generation?
It would be nice to have some mechanism to move enums back and forth between R and C++. I'm not sure what as_sexp()
would do but as_cpp<Enum>
could be:
namespace cpp11 {
template <typename E>
typename std::enable_if<std::is_enum<E>::value, E>::type as_cpp(SEXP from) {
return E(cpp11::as_cpp<typename std::underlying_type<E>::type>(from));
}
}
If this is of interest, I'll polish and make it a proper pull request.
In Rcpp
we had to use the RCPP_EXPOSED_ENUM_NODECL
macro to declare each enum we wished to expose, manually, which sets some templates for Rcpp::as<>
and Rcpp::wrap<>
. IIRC, Rcpp cannot use the is_enum
trait because it's a C++11 thing. https://github.com/RcppCore/Rcpp/blob/f3c5a34e06e774532227470b01c63a8f08ce4313/inst/include/Rcpp/macros/module.h#L76
export is a nice term, but is unfortunately somewhat confusing due to roxygen2 and NAMESPACE using export for exported functions.
[[cpp11::use_from_r]]
seems to match the intent of the attribute best and is nicely self documenting.
Rcpp supports a pkg_types.h file which allows you to declare types used in your package, which can then be used in the cpp11-exports.cpp file.
We should probably do the same, it is a good way to support custom types and headers.
Although it's probably supported on all compilers used on CRAN (even Solaris IIUC) it's probably better to stick to the standard include guards.
cpp11::cpp_source(code = '
#include <cpp11.hpp>
enum class Color : char { red, green = 20, blue };
[[cpp11::register]]
void fun(SEXP value) {
cpp11::as_cpp<Color>(value);
}
', quiet = FALSE)
#> clang++ -mmacosx-version-min=10.13 -std=gnu++11 -I"/Library/Frameworks/R.framework/Resources/include" -DNDEBUG -I/Users/romainfrancois/.R/library/4.0/cpp11/include -I/usr/local/include -fPIC -Wall -O3 -Wall -Wimplicit-int-float-conversion -c /private/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T/RtmpzSpGdd/filef6b4538517d5/src/code_0.cpp -o /private/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T/RtmpzSpGdd/filef6b4538517d5/src/code_0.o
#> In file included from /private/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T/RtmpzSpGdd/filef6b4538517d5/src/code_0.cpp:2:
#> In file included from /Users/romainfrancois/.R/library/4.0/cpp11/include/cpp11.hpp:5:
#> /Users/romainfrancois/.R/library/4.0/cpp11/include/cpp11/as.hpp:80:27: error: call to function 'as_cpp' that is neither visible in the template definition nor found by argument-dependent lookup
#> return static_cast<E>(as_cpp<typename std::underlying_type<E>::type>(from));
#> ^
#> /private/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T/RtmpzSpGdd/filef6b4538517d5/src/code_0.cpp:8:10: note: in instantiation of function template specialization 'cpp11::as_cpp<Color>' requested here
#> cpp11::as_cpp<Color>(value);
#> ^
#> /Users/romainfrancois/.R/library/4.0/cpp11/include/cpp11/as.hpp:143:12: note: 'as_cpp' should be declared prior to the call site or in the global namespace
#> is_char<T> as_cpp(SEXP from) {
#> ^
#> 1 error generated.
#> make: *** [/private/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T/RtmpzSpGdd/filef6b4538517d5/src/code_0.o] Error 1
#> Error in dyn.load(shared_lib, local = TRUE, now = TRUE): unable to load shared object '/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T//RtmpzSpGdd/filef6b4538517d5/src/code_0.so':
#> dlopen(/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T//RtmpzSpGdd/filef6b4538517d5/src/code_0.so, 6): image not found
fun(0L)
#> Error in .Call("_code_0_fun", value, PACKAGE = "code_0"): "_code_0_fun" not available for .Call() for package "code_0"
Created on 2020-08-05 by the reprex package (v0.3.0.9001)
Would it be useful to have the initializer lists constructors also for the non writable classes, or should they really only be constructed from SEXP
, e.g. I enjoy:
cpp11::cpp_function('cpp11::writable::strings words() {
return {"person", "man", "woman", "camera", "tv"};
}')
words()
#> [1] "person" "man" "woman" "camera" "tv"
but this would be useful too:
cpp11::cpp_function('cpp11::strings words() {
return {"person", "man", "woman", "camera", "tv"};
}', quiet = FALSE)
#> clang++ -mmacosx-version-min=10.13 -std=gnu++11 -I"/Library/Frameworks/R.framework/Resources/include" -DNDEBUG -I/Users/romainfrancois/.R/library/4.0/cpp11/include -I/usr/local/include -fPIC -Wall -O3 -Wall -Wimplicit-int-float-conversion -c /private/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T/RtmphIuzJv/filebd3a13b05d00/src/code_1.cpp -o /private/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T/RtmphIuzJv/filebd3a13b05d00/src/code_1.o
#> /private/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T/RtmphIuzJv/filebd3a13b05d00/src/code_1.cpp:6:10: error: no matching constructor for initialization of 'cpp11::strings' (aka 'r_vector<cpp11::r_string>')
#> return {"person", "man", "woman", "camera", "tv"};
#> ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#> /Users/romainfrancois/.R/library/4.0/cpp11/include/cpp11/r_vector.hpp:61:3: note: candidate constructor not viable: requires 2 arguments, but 5 were provided
#> r_vector(SEXP data, bool is_altrep);
#> ^
#> /Users/romainfrancois/.R/library/4.0/cpp11/include/cpp11/r_vector.hpp:59:3: note: candidate constructor not viable: requires single argument 'data', but 5 arguments were provided
#> r_vector(SEXP data);
#> ^
#> /Users/romainfrancois/.R/library/4.0/cpp11/include/cpp11/r_vector.hpp:91:3: note: candidate constructor not viable: requires single argument 'rhs', but 5 arguments were provided
#> r_vector(const r_vector& rhs) {
#> ^
#> /Users/romainfrancois/.R/library/4.0/cpp11/include/cpp11/r_vector.hpp:57:3: note: candidate constructor not viable: requires 0 arguments, but 5 were provided
#> r_vector() = default;
#> ^
#> 1 error generated.
#> make: *** [/private/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T/RtmphIuzJv/filebd3a13b05d00/src/code_1.o] Error 1
#> Error in dyn.load(shared_lib, local = TRUE, now = TRUE): unable to load shared object '/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T//RtmphIuzJv/filebd3a13b05d00/src/code_1.so':
#> dlopen(/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T//RtmphIuzJv/filebd3a13b05d00/src/code_1.so, 6): image not found
words()
#> Error in .Call("_code_1_words", PACKAGE = "code_1"): "_code_1_words" not available for .Call() for package "code_1"
Created on 2020-07-24 by the reprex package (v0.3.0.9001)
Following along with the "Get started with cpp11" vignette (https://cpp11.r-lib.org/articles/cpp11.html), the cpp code seems to be getting garbled when the vignette is produced. For example, the vignette example lines 117-121 (https://github.com/r-lib/cpp11/blob/master/vignettes/cpp11.Rmd)
int one() {
return 1;
}
is rendered in the vignette (https://cpp11.r-lib.org/articles/cpp11.html#no-inputs-scalar-output-1) as
cpp_function('int one() {
return 1;
}'p_function('int one() {
return 1;
}')
Somehow the code isn't parsing correctly such that part of the code is pasted into itself. This might be a pkgdown issue, because my local copy of the vignette looks fine.
This is necessary to ensure the correct definition for RBoolean
is created.
E.g. here:
cpp11/inst/include/cpp11/function.hpp
Lines 54 to 56 in d4fc650
Perhaps this could return a proxy object that is convertible to the user-requested type (function
, SEXP
, and so on)?
Prepare for release:
usethis::use_cran_comments()
devtools::check(remote = TRUE, manual = TRUE)
devtools::check_win_devel()
rhub::check_for_cran()
cran-comments.md
Submit to CRAN:
usethis::use_version('minor')
devtools::submit_cran()
Wait for CRAN...
usethis::use_news_md()
usethis::use_github_release()
usethis::use_dev_version()
Invited to consider the possibility to add the following methods:
empty
is_na
I've read this a few times and I confess I cannot make heads or tails of the results. Perhaps I'm just reading it wrong. I thought I'd mention it incase there is a bug. I'm usually adept at interpreting plots, so if its correct, perhaps there is another way to present the data?
cpp11::cpp_function('int twice(const int& x) {
return x * 2;
}', quiet = FALSE)
#> clang++ -mmacosx-version-min=10.13 -std=gnu++11 -I"/Library/Frameworks/R.framework/Resources/include" -DNDEBUG -I/Users/romainfrancois/.R/library/4.0/cpp11/include -I/usr/local/include -fPIC -Wall -O3 -Wall -Wimplicit-int-float-conversion -c /private/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T/RtmpRFFnOt/filedea24914c969/src/code_0.cpp -o /private/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T/RtmpRFFnOt/filedea24914c969/src/code_0.o
#> clang++ -mmacosx-version-min=10.13 -std=gnu++11 -I"/Library/Frameworks/R.framework/Resources/include" -DNDEBUG -I/Users/romainfrancois/.R/library/4.0/cpp11/include -I/usr/local/include -fPIC -Wall -O3 -Wall -Wimplicit-int-float-conversion -c /private/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T/RtmpRFFnOt/filedea24914c969/src/cpp11.cpp -o /private/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T/RtmpRFFnOt/filedea24914c969/src/cpp11.o
#> /private/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T/RtmpRFFnOt/filedea24914c969/src/cpp11.cpp:7:47: error: no matching function for call to 'as_cpp'
#> return cpp11::as_sexp(twice(cpp11::unmove(cpp11::as_cpp<const int&>(x))));
#> ^~~~~~~~~~~~~~~~~~~~~~~~~
#> /Users/romainfrancois/.R/library/4.0/cpp11/include/cpp11/as.hpp:20:31: note: candidate template ignored: requirement 'std::is_constructible<const int &, SEXPREC *>::value' was not satisfied [with T = const int &]
#> is_constructible_from_sexp<T> as_cpp(SEXP from) {
#> ^
#> /Users/romainfrancois/.R/library/4.0/cpp11/include/cpp11/as.hpp:46:16: note: candidate template ignored: requirement 'std::is_integral<const int &>::value' was not satisfied [with T = const int &]
#> is_integral<T> as_cpp(SEXP from) {
#> ^
#> /Users/romainfrancois/.R/library/4.0/cpp11/include/cpp11/as.hpp:70:15: note: candidate template ignored: requirement 'std::is_same<int, bool>::value' was not satisfied [with T = const int &]
#> is_logical<T> as_cpp(SEXP from) {
#> ^
#> /Users/romainfrancois/.R/library/4.0/cpp11/include/cpp11/as.hpp:87:28: note: candidate template ignored: requirement 'std::is_floating_point<const int &>::value' was not satisfied [with T = const int &]
#> is_floating_point_value<T> as_cpp(SEXP from) {
#> ^
#> /Users/romainfrancois/.R/library/4.0/cpp11/include/cpp11/as.hpp:109:12: note: candidate template ignored: requirement 'std::is_same<int, char>::value' was not satisfied [with T = const int &]
#> is_char<T> as_cpp(SEXP from) {
#> ^
#> /Users/romainfrancois/.R/library/4.0/cpp11/include/cpp11/as.hpp:129:37: note: candidate template ignored: requirement 'std::is_constructible<int, const char *>::value' was not satisfied [with T = const int &]
#> is_constructible_from_const_char<T> as_cpp(SEXP from) {
#> ^
#> /Users/romainfrancois/.R/library/4.0/cpp11/include/cpp11/r_vector.hpp:933:43: note: candidate template ignored: substitution failure [with C = const int &]: 'std::__1::decay<const int &>::type' (aka 'int') is not a class, namespace, or enumeration
#> is_container_but_not_sexp_or_string<C, T> as_cpp(SEXP from) {
#> ^
#> /Users/romainfrancois/.R/library/4.0/cpp11/include/cpp11/r_vector.hpp:946:28: note: candidate template ignored: substitution failure [with C = const int &]: 'std::__1::decay<const int &>::type' (aka 'int') is not a class, namespace, or enumeration
#> is_vector_of_strings<C, T> as_cpp(SEXP from) {
#> ^
#> 1 error generated.
#> make: *** [/private/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T/RtmpRFFnOt/filedea24914c969/src/cpp11.o] Error 1
#> Error in dyn.load(shared_lib, local = TRUE, now = TRUE): unable to load shared object '/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T//RtmpRFFnOt/filedea24914c969/src/code_0.so':
#> dlopen(/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T//RtmpRFFnOt/filedea24914c969/src/code_0.so, 6): image not found
Created on 2020-07-21 by the reprex package (v0.3.0.9001)
Rcpp
deals with this with the extra layer of indirection given by the various Rcpp::traits::input_parameter<>
classes:
Rcpp::cppFunction('int twice(const int& x) {
return x * 2;
}', verbose = TRUE)
#>
#> Generated code for function definition:
#> --------------------------------------------------------
#>
#> #include <Rcpp.h>
#>
#> using namespace Rcpp;
#>
#> // [[Rcpp::export]]
#> int twice(const int& x) {
#> return x * 2;
#> }
#>
#> Generated extern "C" functions
#> --------------------------------------------------------
#>
#>
#> #include <Rcpp.h>
#> // twice
#> int twice(const int& x);
#> RcppExport SEXP sourceCpp_1_twice(SEXP xSEXP) {
#> BEGIN_RCPP
#> Rcpp::RObject rcpp_result_gen;
#> Rcpp::RNGScope rcpp_rngScope_gen;
#> Rcpp::traits::input_parameter< const int& >::type x(xSEXP);
#> rcpp_result_gen = Rcpp::wrap(twice(x));
#> return rcpp_result_gen;
#> END_RCPP
#> }
#>
#> Generated R functions
#> -------------------------------------------------------
#>
#> `.sourceCpp_1_DLLInfo` <- dyn.load('/private/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T/Rtmp5bfOwE/sourceCpp-x86_64-apple-darwin17.0-1.0.5/sourcecpp_df104719c3e9/sourceCpp_2.so')
#>
#> twice <- Rcpp:::sourceCppFunction(function(x) {}, FALSE, `.sourceCpp_1_DLLInfo`, 'sourceCpp_1_twice')
#>
#> rm(`.sourceCpp_1_DLLInfo`)
#>
#> Building shared library
#> --------------------------------------------------------
#>
#> DIR: /private/var/folders/4b/hn4fq98s6810s4ccv2f9hm2h0000gn/T/Rtmp5bfOwE/sourceCpp-x86_64-apple-darwin17.0-1.0.5/sourcecpp_df104719c3e9
#>
#> /Library/Frameworks/R.framework/Resources/bin/R CMD SHLIB -o 'sourceCpp_2.so' 'filedf107957208b.cpp'
twice(21L)
#> [1] 42
Created on 2020-07-21 by the reprex package (v0.3.0.9001)
In that case Rcpp::traits::input_parameter< const int& >
holds an int
and exposes it as a const int&
, and this allows for extensions, e.g. in arrow
many of the functions take const std::shared_ptr<T>&
and arrow
has a custom input_parameter<const std::shared_ptr<T>&>
that knows how to extract the information from the R6 object that is passed in.
I don't think it can be done in cpp11
with the current code generation.
This introduces unnecessary boilerplate when using a function like Rf_translateCharUTF8
which returns const char*
:
cpp11/inst/include/cpp11/as.hpp
Lines 134 to 136 in 030f91d
It would be fairly straightforward to extend these to allow:
return unwind_protect([&] { return Rf_translateCharUTF8(STRING_ELT(from, 0)); })[0];
Or even (provided STRING_ELT
doesn't require protection):
return safe[Rf_translateCharUTF8](STRING_ELT(from, 0))[0];
Sometimes for best performance, in-place modification is really needed. For example, if one needs a cpp11 function that in-place sorts an R vector without making a copy just like std::sort
, or a cpp11 functions that performs in-place winsorization for speed (because it knows that the input vector is only intermediate and could be changed to avoid more allocation). I'm wondering if there's a decent way to do so without using DATAPTR
from R C API?
A major point of using Rcpp is for speed but I'm wondering if modifying an R vector by reference is completely prohibited in cpp11?
Looking here:
cpp11/inst/include/cpp11/as.hpp
Lines 109 to 115 in cf7391b
If an error occurs during translation, c_p
will remain as a nullptr
and then the attempt to access the zero-th element will likely crash.
R strings seem like a pretty perfect use case for std::string_view. For compilers that don't support c++17, there are backports available. Any interest in a pull request?
This package is very exciting - I'm exploring using it on a couple of projects at the moment. I've noticed that the cpp11.cpp and cpp11.R files that are created have a trailing blank line. I would create a PR to fix it, but this looks intentional (
Line 88 in 0a202e5
Line 43 in 0a202e5
Also, how stable is the API likely to be? I recognise this is very much a work in progress, but also clearly something you've been thinking about for a bit.
I find it a bit confusing to read code with a templated class called vector
that is not std::vector
. How about cpp11::r_vector<>
?
I was doing some benchmarking and got some strange results.
I think I got it minimal enough now. It appears that any function when being defined adds calling time to any previous functions.
library(cpp11)
cpp_function("void void_a() {}")
cpp_function("void void_b() {}")
bm <- bench::mark(
void_a(),
void_b()
)
plot(bm)
#> Loading required namespace: tidyr
cpp_function("void void_b() {}")
cpp_function("void void_a() {}")
bm <- bench::mark(
void_a(),
void_b()
)
plot(bm)
Created on 2020-06-17 by the reprex package (v0.3.0)
library(cpp11)
cpp_function("void void_a() {}")
cpp_function("void void_b() {}")
cpp_function("void void_c() {}")
cpp_function("void void_d() {}")
cpp_function("void void_e() {}")
bm <- bench::mark(
void_a(),
void_b(),
void_c(),
void_d(),
void_e()
)
plot(bm)
#> Loading required namespace: tidyr
Created on 2020-06-17 by the reprex package (v0.3.0)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.