From c5663f6938f7e25168bf9a1a98328dd899a022b0 Mon Sep 17 00:00:00 2001 From: Dirk Eddelbuettel Date: Wed, 8 Apr 2026 08:14:16 -0500 Subject: [PATCH 1/4] Enhance Rcpp::Nullable::as with explicit cast (Closes #1470) --- ChangeLog | 5 +++++ inst/include/Rcpp/Nullable.h | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index ce2faf721..286c1056c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2026-04-08 Dirk Eddelbuettel + + * inst/include/Rcpp/Nullable.h (as): Enhance by adding an explicit + Rcpp::as() aiding cases where implicit as<> does not suffice + 2026-04-07 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Roll micro version and date (twice) diff --git a/inst/include/Rcpp/Nullable.h b/inst/include/Rcpp/Nullable.h index 53704ffb8..1ad72b843 100644 --- a/inst/include/Rcpp/Nullable.h +++ b/inst/include/Rcpp/Nullable.h @@ -126,7 +126,7 @@ namespace Rcpp { /** * Returns m_sexp as a T */ - inline T as() { return get(); } + inline T as() { return Rcpp::as(get()); } /** * Return a clone of m_sexp as a T From d0afd1cb27cee531c6907d48292c1f71e67c308f Mon Sep 17 00:00:00 2001 From: Dirk Eddelbuettel Date: Thu, 9 Apr 2026 07:41:37 -0500 Subject: [PATCH 2/4] Add operator T --- ChangeLog | 4 ++++ inst/include/Rcpp/Nullable.h | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/ChangeLog b/ChangeLog index 286c1056c..ec0ad88e7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2026-04-09 Dirk Eddelbuettel + + * inst/include/Rcpp/Nullable.h (T): Also add 'operator T()' + 2026-04-08 Dirk Eddelbuettel * inst/include/Rcpp/Nullable.h (as): Enhance by adding an explicit diff --git a/inst/include/Rcpp/Nullable.h b/inst/include/Rcpp/Nullable.h index 1ad72b843..b35851b5c 100644 --- a/inst/include/Rcpp/Nullable.h +++ b/inst/include/Rcpp/Nullable.h @@ -81,6 +81,16 @@ namespace Rcpp { return m_sexp; } + /** + * operator T() to return nullable object + * + * @throw 'not initialized' if object has not been set + */ + inline operator T() const { + checkIfSet(); + return Rcpp::as(m_sexp); + } + /** * get() accessor for object * From cd69a8324b28c95d0536a3e77b4be586c6d10b7e Mon Sep 17 00:00:00 2001 From: Dirk Eddelbuettel Date: Thu, 9 Apr 2026 08:11:14 -0500 Subject: [PATCH 3/4] Conditrion nullable test on R 4.3.0 or later --- inst/tinytest/cpp/misc.cpp | 2 ++ inst/tinytest/test_misc.R | 8 +++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/inst/tinytest/cpp/misc.cpp b/inst/tinytest/cpp/misc.cpp index 87271e5d3..ec516631e 100644 --- a/inst/tinytest/cpp/misc.cpp +++ b/inst/tinytest/cpp/misc.cpp @@ -217,6 +217,7 @@ SEXP testNullableIsUsable(const Nullable& M) { } } +#if R_VERSION > R_Version(4,3,0) // [[Rcpp::export]] String testNullableString(Rcpp::Nullable param = R_NilValue) { if (param.isNotNull()) @@ -224,6 +225,7 @@ String testNullableString(Rcpp::Nullable param = R_NilValue) { else return String(""); } +#endif // [[Rcpp::export]] void messageWrapper(SEXP s) { diff --git a/inst/tinytest/test_misc.R b/inst/tinytest/test_misc.R index 9fb5f50d9..bb789df74 100644 --- a/inst/tinytest/test_misc.R +++ b/inst/tinytest/test_misc.R @@ -168,9 +168,11 @@ expect_equal( testNullableIsUsable(M), M) # test.NullableIsUsableFalse <- function() { expect_true(is.null(testNullableIsUsable(NULL))) -# test.NullableString <- function() { -expect_equal(testNullableString(), "") -expect_equal(testNullableString("blah"), "blah") +## test.NullableString <- function() { +if (getRversion() > "4.3.0") { + expect_equal(testNullableString(), "") + expect_equal(testNullableString("blah"), "blah") +} # test.bib <- function() { expect_true(nchar(Rcpp:::bib()) > 0, info="bib file") From 075dfc712ca6b7ee47366a7773b7ea1cd68f4942 Mon Sep 17 00:00:00 2001 From: Dirk Eddelbuettel Date: Thu, 9 Apr 2026 08:25:46 -0500 Subject: [PATCH 4/4] Move the conditional to operator T() --- ChangeLog | 1 + inst/include/Rcpp/Nullable.h | 2 ++ inst/tinytest/cpp/misc.cpp | 2 -- inst/tinytest/test_misc.R | 6 ++---- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index ec0ad88e7..077086573 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,7 @@ 2026-04-09 Dirk Eddelbuettel * inst/include/Rcpp/Nullable.h (T): Also add 'operator T()' + (conditional on R (>= 4.3.0) as older versions croak) 2026-04-08 Dirk Eddelbuettel diff --git a/inst/include/Rcpp/Nullable.h b/inst/include/Rcpp/Nullable.h index b35851b5c..27085b8fa 100644 --- a/inst/include/Rcpp/Nullable.h +++ b/inst/include/Rcpp/Nullable.h @@ -81,6 +81,7 @@ namespace Rcpp { return m_sexp; } +#if R_VERSION > R_Version(4,3,0) /** * operator T() to return nullable object * @@ -90,6 +91,7 @@ namespace Rcpp { checkIfSet(); return Rcpp::as(m_sexp); } +#endif /** * get() accessor for object diff --git a/inst/tinytest/cpp/misc.cpp b/inst/tinytest/cpp/misc.cpp index ec516631e..87271e5d3 100644 --- a/inst/tinytest/cpp/misc.cpp +++ b/inst/tinytest/cpp/misc.cpp @@ -217,7 +217,6 @@ SEXP testNullableIsUsable(const Nullable& M) { } } -#if R_VERSION > R_Version(4,3,0) // [[Rcpp::export]] String testNullableString(Rcpp::Nullable param = R_NilValue) { if (param.isNotNull()) @@ -225,7 +224,6 @@ String testNullableString(Rcpp::Nullable param = R_NilValue) { else return String(""); } -#endif // [[Rcpp::export]] void messageWrapper(SEXP s) { diff --git a/inst/tinytest/test_misc.R b/inst/tinytest/test_misc.R index bb789df74..08df4b5cd 100644 --- a/inst/tinytest/test_misc.R +++ b/inst/tinytest/test_misc.R @@ -169,10 +169,8 @@ expect_equal( testNullableIsUsable(M), M) expect_true(is.null(testNullableIsUsable(NULL))) ## test.NullableString <- function() { -if (getRversion() > "4.3.0") { - expect_equal(testNullableString(), "") - expect_equal(testNullableString("blah"), "blah") -} +expect_equal(testNullableString(), "") +expect_equal(testNullableString("blah"), "blah") # test.bib <- function() { expect_true(nchar(Rcpp:::bib()) > 0, info="bib file")