diff --git a/.gitignore b/.gitignore index 001769b5..ee4d3997 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ README.html .clangd/ cpp11test/compile_commands.json cpp11test/src/Makevars +cpp11test/src/*.o +cpp11test/src/*.so compile_flags.txt inst/doc vignettes/*_cache diff --git a/NEWS.md b/NEWS.md index 7dcb09ca..45ddf4fc 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,7 @@ # cpp11 (development version) +* `as_cpp()` now allows enumeration `E` (#52, @bkietz) + * `writable::logicals::operator=()` now allows C++ boolean values (#57, @romainfrancois) * `list::const_iterator::operator*()` added so iterators could be used on list objects (#60, @romainfrancois) diff --git a/cpp11test/src/test-as.cpp b/cpp11test/src/test-as.cpp index 33f2ac84..017e9ad5 100644 --- a/cpp11test/src/test-as.cpp +++ b/cpp11test/src/test-as.cpp @@ -75,6 +75,19 @@ context("as_cpp-C++") { UNPROTECT(3); } + test_that("as_cpp(INTSEXP)") { + enum Response { YES, NO, MAYBE }; + SEXP r = PROTECT(Rf_allocVector(INTSXP, 1)); + + for (Response e : {YES, NO, MAYBE, static_cast(42)}) { + INTEGER(r)[0] = static_cast(e); + auto x = cpp11::as_cpp(r); + expect_true(x == e); + } + + UNPROTECT(1); + } + test_that("as_cpp(REALSXP)") { SEXP r = PROTECT(Rf_allocVector(REALSXP, 1)); REAL(r)[0] = 1.2; diff --git a/inst/include/cpp11/as.hpp b/inst/include/cpp11/as.hpp index 8ecd7a64..88e86503 100644 --- a/inst/include/cpp11/as.hpp +++ b/inst/include/cpp11/as.hpp @@ -71,6 +71,18 @@ is_integral as_cpp(SEXP from) { return T(); } +template +using is_enum = typename std::enable_if::value, E>::type; + +template +is_enum as_cpp(SEXP from) { + if (Rf_isInteger(from)) { + return static_cast(as_cpp::type>(from)); + } + + stop("Expected single integer value"); +} + template using is_logical = typename std::enable_if::type, bool>::value,