[Rcpp-devel] Extract a function from a list and create a call

Romain Francois romain at r-enthusiasts.com
Sat Mar 20 08:53:42 CET 2010


Hello,

The issue with CharacterVector is that the proxy classes : 
"string_name_proxy" and "string_proxy" only have implicit conversion to 
SEXP and char* :

operator char* (){
	return get() ;
}	
operator SEXP(){
	return ::Rf_mkString(get()) ;
}

i.e. they don't have implicit conversion to std::string. We can't have 
both implicit conversions to char* and std::string because it causes 
ambiguities and the compiler is much unhappy.

So given a CharacterVector, we can grab the first element as a 
std::string using one of these options:

require( Rcpp )
require( inline )

fx <- cfunction( signature( x_ = "character" ), '
CharacterVector x(x_);

// x[0] is implicitely converted to a char* and the string( char*)
// constructor is used
std::string y( x[0] ) ;

// using string::operator=( char* ) with a std::string created before
std::string z ;
z = x[0] ;

// but this does not work
// std::string foo = x[0] ;
// because there is no implicit conversion proxy -> std::string

', Rcpp = TRUE, includes = "using namespace Rcpp;" )

Romain


Le 19/03/10 21:42, Romain Francois a écrit :
>
> Le 19/03/10 21:26, Douglas Bates a écrit :
>>
>> By the way, I'm sorry for the misleading subject line in my original
>> post.  When I started the message I was trying to extract one of those
>> functions in the "family" list and create a call.
>>
>>
>> On Fri, Mar 19, 2010 at 3:20 PM, Romain Francois
>> <romain.francois at dbmail.com>   wrote:
>>> Hello,
>>>
>>> The following works for me :
>>>
>>> require( Rcpp )
>>> require( inline )
>>>
>>> fx<- cfunction( signature( data_ = "list" ),
>>> '
>>> List data(data_) ;
>>> std::string family = data["family"] ;
>>> std::string link   = data["link"] ;
>>>
>>> std::cout<<   "family :"<<   family<<   std::endl ;
>>> std::cout<<   "link   :"<<   link<<   std::endl ;
>>>
>>> return R_NilValue ;
>>> ', Rcpp = TRUE, includes = "using namespace Rcpp;" )
>>>
>>>> fx( )
>>> family : poisson
>>> link   : log
>>> NULL
>>>
>>>
>>>
>>> But we have an issue with the proxy class we use in CharacterVector. It
>>> seems if you have a CharacterVector :
>>>
>>> CharacterVector family = data["family"] ;
>>>
>>> you can grab one element as a C string (const char*)
>>>
>>> const char* fam = family[0] ;
>>>
>>> but not as a std::string for some reason. some investigation needed.
>>
>> I think the underlying question for me is why the Rcpp::Vector
>> template does not take both the element type and the Rtype as
>> arguments.  Having the () and [] operators in the template return a
>> Proxy type may be necessary but I don't know enough about templates to
>> decide why.  If I have instantiated the NumericVector class from the
>> template as wrapping a REALSXP then the only thing I can imagine the
>> () and [] operators returning is a double.
>
> Yes. For simple vectors (integer, raw, logical, numeric, complex), the
> indexers return the obvious type (int, Rbyte, int, double, Rcomplex).
>
> For other vector types, it is more complex and we have to resort to
> proxy classes. so List::operator[] returns an instance of some proxy
> class, and the proxy class is supposed to handle anything you throw at it :
> - if the proxy is used on the lhs, an implcit call to wrap is made so
> that what gets stored into the list is a SEXP, via SET_VECTOR_ELT. This
> is why this works :
>
> data["foo"] = 10 ;
>
> data["foo"] creates a proxy and the proxy class has the magic templated
> operator= :
>
> template<typename T>
> generic_name_proxy&  operator=( const T&  rhs ){
> 	set( ::Rcpp::wrap(rhs) ) ;
> 	return *this ;
> }
> 		
> used with T=int in this case, so anything that can be wrapped can be
> assigned using this syntax in a list
>
>
> - if the proxy is used on the rhs, an implicit call to as is made to
> attempt to convert what is currently at the given position (which is a
> SEXP) to whatever is requested. So in:
>
> CharacterVector family = data["family"] ;
>
> data["family"] creates a proxy and the proxy has the magic implicit
> conversion operator :
>
> template<typename T>
> operator T(){
> 	return ::Rcpp::as<T>( get() ) ;
> }
>
> so that in this case T is CharacterVector
>
> In this instance the proxy class is generic_name_proxy if you want to
> have a look in the code, it is "generic_proxy" if what is inside the
> brackets is an int.
>
> We seem to have an issue with the proxies that are used with
> CharacterVector, and I'll have a look tomorrow.
>
> Romain
>
>> Part of the problem for me is what to do with the result of () or []
>> from an Rcpp::List.  I can't manage to convince the compiler that it's
>> some kind of Rcpp::RObject, which I would say it has to be.
>>
>>>
>>> Romain
>>>
>>>
>>> Le 19/03/10 20:21, Douglas Bates a écrit :
>>>>
>>>> I must be missing something horribly obvious but I have now spent
>>>> several hours trying to find a way to extract a character string from
>>>> a list.  I am more-or-less certain that I am copying a construction in
>>>> the unitTests/runit.CharacterVector.R but the compiler just keeps
>>>> spitting out error messages at me.
>>>>
>>>> The background is that a glm "family" object in R is a named list (or
>>>> should be, it has an S3 class but that doesn't mean anything about the
>>>> structure).  The standard ones look like
>>>>
>>>>> str(poisson())
>>>>
>>>> List of 12
>>>>    $ family    : chr "poisson"
>>>>    $ link      : chr "log"
>>>>    $ linkfun   :function (mu)
>>>>    $ linkinv   :function (eta)
>>>>    $ variance  :function (mu)
>>>>    $ dev.resids:function (y, mu, wt)
>>>>    $ aic       :function (y, n, mu, wt, dev)
>>>>    $ mu.eta    :function (eta)
>>>>    $ initialize:  expression({     if (any(y<     0))
>>>> stop("negative values not allowed for the Poisson family")     n<-
>>>> rep.int(1, nobs)     mustart<- y + 0.1 })
>>>>    $ validmu   :function (mu)
>>>>    $ valideta  :function (eta)
>>>>    $ simulate  :function (object, nsim)
>>>>    - attr(*, "class")= chr "family"
>>>>
>>>> All I want to do is to take such a list and extract the "family" and
>>>> "link" strings as std::string.  If the name of the Rcpp::List object
>>>> in the C++ code is lst, I can get as far as
>>>>
>>>> StringVector fam = lst["family"];
>>>>
>>>> but after that it all turns to custard.  In the class I am defining
>>>> the family member is declared as a std::string.  In the constructor
>>>> for the class from a List object I try
>>>>
>>>> family = Rcpp::as<std::string>(fam[0]);
>>>>
>>>> or even, mimicking a couple of the tests in
>>>> unitTests/runit.CharacterVector.R,
>>>>
>>>> family += fam[0];
>>>>
>>>> but I have not been able to construct anything that my compiler will
>>>> accept.
>>>>
>>>> So, how do I get the value of one of the elements of a CharacterVector
>>>> (or StringVector, I think they are synonyms) as a std::string, short
>>>> of using std::string(CHAR(STRING_ELT(fam, 0))
>
>


-- 
Romain Francois
Professional R Enthusiast
+33(0) 6 28 91 30 30
http://romainfrancois.blog.free.fr
|- http://tr.im/OIXN : raster images and RImageJ
|- http://tr.im/OcQe : Rcpp 0.7.7
`- http://tr.im/O1wO : highlight 0.1-5



More information about the Rcpp-devel mailing list