Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
2026-06-26 Kevin Ushey <kevinushey@gmail.com>

* inst/include/Rcpp/proxy/AttributeProxy.h: Do not rely on get__()
in attribute accessors so that classes such as ListOf compile
* inst/tinytest/cpp/ListOf.cpp: Added tests
* inst/tinytest/test_listof.R: Idem

2026-06-23 Jeroen Ooms <jeroenooms@gmail.com>

* Add templated integer-index overload on platforms without
Expand Down
3 changes: 3 additions & 0 deletions inst/NEWS.Rd
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@
has been fixed (Kevin in \ghpr{1475} fixing \ghit{1474})
\item The \code{Nullable::operatorT()} has been added as a 'opt-out'
(Dirk in \ghpr{1477} with coordination in \ghit{1472})
\item The attribute accessors in \code{AttributeProxyPolicy} no longer
rely on \code{get__()} so that classes such as \code{ListOf} compile
(Kevin in \ghpr{1484} fixing \ghit{1483})
}
\item Changes in Rcpp Documentation:
\itemize{
Expand Down
4 changes: 2 additions & 2 deletions inst/include/Rcpp/proxy/AttributeProxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class AttributeProxyPolicy {
v.push_back(std::string(CHAR(STRING_ELT(attrs, i))));
}
#else
SEXP attrs = ATTRIB( static_cast<const CLASS&>(*this).get__());
SEXP attrs = ATTRIB( static_cast<const CLASS&>(*this) );
while( attrs != R_NilValue ){
v.push_back( std::string(CHAR(PRINTNAME(TAG(attrs)))) ) ;
attrs = CDR( attrs ) ;
Expand All @@ -97,7 +97,7 @@ class AttributeProxyPolicy {

bool hasAttribute(const std::string& attr) const {
#if R_VERSION >= R_Version(4, 6, 0)
return R_hasAttrib(static_cast<const CLASS&>(*this).get__(), Rf_install(attr.c_str()));
return R_hasAttrib(static_cast<const CLASS&>(*this), Rf_install(attr.c_str()));
#else
return static_cast<const CLASS&>(*this).attr(attr) != R_NilValue;
#endif
Expand Down
10 changes: 10 additions & 0 deletions inst/tinytest/cpp/ListOf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,13 @@ CharacterVector listof_names(ListOf<NumericVector> x) {
SEXP listof_attr_foo(ListOf<NumericVector> x) {
return x.attr("foo");
}

// [[Rcpp::export]]
bool listof_has_attr(ListOf<NumericVector> x, std::string name) {
return x.hasAttribute(name);
}

// [[Rcpp::export]]
std::vector<std::string> listof_attribute_names(ListOf<NumericVector> x) {
return x.attributeNames();
}
12 changes: 12 additions & 0 deletions inst/tinytest/test_listof.R
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,15 @@ expect_equal(listof_names(l), c("a", "b", "c"))
l <- list(a = 1L)
attr(l, "foo") <- "bar"
expect_equal(listof_attr_foo(l), "bar")

# test.ListOf.has.attribute <- function() { # GH issue #1483
l <- list(a = 1L)
attr(l, "foo") <- "bar"
expect_true(listof_has_attr(l, "foo"))
expect_true(listof_has_attr(l, "names"))
expect_false(listof_has_attr(l, "missing"))

# test.ListOf.attribute.names <- function() { # GH issue #1483
l <- list(a = 1L)
attr(l, "foo") <- "bar"
expect_true(all(c("names", "foo") %in% listof_attribute_names(l)))
Loading