Skip to content

[Rcpp-devel] Problem exposing constructor taking std::vector of user defined class to R using Rcpp-attributes and Rcpp-modules

7 messages · Luke.Domanski at csiro.au, Dirk Eddelbuettel, Romain Francois

#
Hi All,

I running into some problems using a combination of Rcpp-attributes and Rcpp-modules to expose a C++ class library, and would appreciate your help.

I am trying to expose to R the constructor of a C++ class template which accepts a std vector of the template parameter T as input, as shown in the following toy class A used to replicate the problem:

template <class T> class A {
    public:
        std::vector<T> vec_of_T;

        A( std::vector<T> in_vec );
};

The class and constructor will only be exposed to R as a specific instantiation of the class A with template parameter T=class B, i.e. A<B>, where B is implemented in both C++ and R, and the C++ implementation of B has a constructor B::B(SEXP):

#include <RcppCommon.h>

class B {
    public:
        int id;

        B (SEXP b);
        B (int id=-1);
};

/*** R
# Reference Class of B
B_R <- setRefClass( "B_R",
    fields = list(id="numeric")
)
*/

template <class T> class A {
    public:
        std::vector<T> vec_of_T;

        A( std::vector<T> in_vec );
};

#include <Rcpp.h>

B::B(SEXP b){
    Rcpp::Reference in_b(b);
    id=in_b.field("id");
}

B::B(int id){
    this->id=id;
}

The idea is to allow an R vector of Reference Class objects B_R to be passed to the C++ class A<B> constructor. To achieve this I have used the following Rcpp-modules directly after the preceding code:

using namespace Rcpp;

RCPP_MODULE(testing) {

    class_< A<B> >("A")

    .constructor< std::vector<B> >()
    ;
}

I then use Rcpp-attributed sourceCpp() to compile the code from the R prompt, and generate the R bindings to the C++ class A<B>.
However, when I run the above sourceCpp command I get the following error which is stretching my understanding on both C++ and Rcpp:


C:/PROGRA~1/R/R-30~1.1/bin/i386/R CMD SHLIB -o "sourceCpp_42052.dll" "test.cpp"
g++ -m32 -I"C:/PROGRA~1/R/R-30~1.1/include" -DNDEBUG     -I"C:/Users/me/Documents/R/win-library/3.0/Rcpp/include"  -I"d:/RCompile/CRANpkg/extralibs64/local/include"     -O2 -Wall  -mtune=core2 -c test.cpp -o test.o
In file included from C:/Users/me/Documents/R/win-library/3.0/Rcpp/include/RcppCommon.h:110:0,
                 from test.cpp:1:
C:/Users/me/Documents/R/win-library/3.0/Rcpp/include/Rcpp/internal/export.h: In function 'void Rcpp::internal::export_range(SEXP, InputIterator) [with InputIterator = __gnu_cxx::__normal_iterator<B*, std::vector<B> >, SEXP = SEXPREC*]':
C:/Users/me/Documents/R/win-library/3.0/Rcpp/include/Rcpp/internal/Exporter.h:47:17:   instantiated from 'T Rcpp::traits::RangeExporter<T>::get() [with T = std::vector<B>]'
C:/Users/me/Documents/R/win-library/3.0/Rcpp/include/Rcpp/as.h:83:33:   instantiated from 'T Rcpp::internal::as(SEXP, Rcpp::traits::r_type_generic_tag) [with T = std::vector<B>, SEXP = SEXPREC*]'
C:/Users/me/Documents/R/win-library/3.0/Rcpp/include/Rcpp/as.h:126:89:   instantiated from 'T Rcpp::as(SEXP) [with T = std::vector<B>, SEXP = SEXPREC*]'
C:/Users/me/Documents/R/win-library/3.0/Rcpp/include/Rcpp/module/Module_generated_Constructor.h:47:43:   instantiated from 'Class* Rcpp::Constructor_1<Class, U0>::get_new(SEXPREC**, int) [with Class = A<B>, U0 = std::vector<B>, SEXP = SEXPREC*]'
test.cpp:59:1:   instantiated from here
C:/Users/me/Documents/R/win-library/3.0/Rcpp/include/Rcpp/internal/export.h:90:4: error: no matching function for call to 'export_range__dispatch(SEXPREC*&, __gnu_cxx::__normal_iterator<B*, std::vector<B> >&, Rcpp::traits::r_type_traits<B>::r_category)'
C:/Users/me/Documents/R/win-library/3.0/Rcpp/include/Rcpp/internal/export.h:90:4: note: candidates are:
C:/Users/me/Documents/R/win-library/3.0/Rcpp/include/Rcpp/internal/export.h:71:14: note: template<class InputIterator, class value_type> void Rcpp::internal::export_range__dispatch(SEXP, InputIterator, Rcpp::traits::r_type_primitive_tag)
C:/Users/me/Documents/R/win-library/3.0/Rcpp/include/Rcpp/internal/export.h:80:8: note: template<class InputIterator, class value_type> void Rcpp::internal::export_range__dispatch(SEXP, InputIterator, Rcpp::traits::r_type_string_tag)
make: *** [test.o] Error 1
Error in sourceCpp(file = "test.cpp", verbose = TRUE) :
  Error 1 occurred building shared library.

Am I missing something in my code?

Thanks in advance,
Luke Domanski.

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.r-forge.r-project.org/pipermail/rcpp-devel/attachments/20130821/962540ec/attachment.html>
#
On 21 August 2013 at 23:21, Luke.Domanski at csiro.au wrote:
| I running into some problems using a combination of Rcpp-attributes and
| Rcpp-modules to expose a C++ class library, and would appreciate your help.

Ahh, that intersection of modules and attributes is still a little rough. 

| I am trying to expose to R the constructor of a C++ class template which
| accepts a std vector of the template parameter T as input, as shown in the
| following toy class A used to replicate the problem:
| 
| template <class T> class A {
|     public:
|         std::vector<T> vec_of_T;
|         A( std::vector<T> in_vec );
| };
| 
| The class and constructor will only be exposed to R as a specific instantiation
| of the class A with template parameter T=class B, i.e. A<B>, where B is
| implemented in both C++ and R, and the C++ implementation of B has a
| constructor B::B(SEXP):
| 
| #include <RcppCommon.h>
| 
| class B {
|     public:
|         int id;
|         B (SEXP b);
|         B (int id=-1);
| };
| 
| /*** R
| # Reference Class of B
| B_R <- setRefClass( "B_R",
|     fields = list(id="numeric")
| )
| */
| 
| 
| template <class T> class A {
|     public:
|         std::vector<T> vec_of_T;
|         A( std::vector<T> in_vec );
| };
| 
|  
| 
| #include <Rcpp.h>
| 
| B::B(SEXP b){
|     Rcpp::Reference in_b(b);
|     id=in_b.field("id");
| }
| 
|  
| B::B(int id){
|     this->id=id;
| }
| 
|  
| 
| The idea is to allow an R vector of Reference Class objects B_R to be passed to
| the C++ class A<B> constructor. To achieve this I have used the following
| Rcpp-modules directly after the preceding code:
| 
|  
| using namespace Rcpp;
| 
| RCPP_MODULE(testing) {
|     class_< A<B> >("A")
|     .constructor< std::vector<B> >()
|     ;
| }
| 
| I then use Rcpp-attributed sourceCpp() to compile the code from the R prompt,
| and generate the R bindings to the C++ class A<B>.
| 
| > sourceCpp(file="test.cpp", verbose=TRUE)
| 
| From my understand of  section 3.2 in Rcpp-introduction.pdf, and what I could
| glean about the handling of RCPP_MODULE declarations within Rcpp-attribute
| (e.g. help(sourceCpp)), the conversion of ?STL vectors of [?] arbitrary types
| that offer a constructor that takes a SEXP? should be supported by Rcpp, and
| Rcpp-attributes should automatically generate wrappers/bindings which utilize
| them.

"Should automatically use available" wrappers/bindings.  

Someone still has to provide the basic as<>() and wrap() code. For common
types we have done.  For custom types you have to do it.
| 
| However, when I run the above sourceCpp command I get the following error which
| is stretching my understanding on both C++ and Rcpp:

[...]  

| Am I missing something in my code?

Could be as simple as your needing to supply as<>() and wrap(). 

I would try something simpler.  Rcpp Modules work well with packages, so
maybe try that first.

Dirk
#
Thanks for your reply Dirk,
Okay.. is it more correct to say "Should use available wrapper to automatically generate bindings"?
Is the constructor B::B(SEXP) I implemented not already the implementation of as<B>(), as per described in section 3.1 "Intrusive extension" of Rcpp-extending?

"As part of its template meta programming dispatch logic, Rcpp::as will attempt to use the constructor of the target class taking a SEXP."

Do you think instead or in addition I should be using "Non intrusive extension" as described in section 3.2 e.g:

namespace Rcpp {
	template <> B as( SEXP ){
		Rcpp::Reference in_b(b);
		id=in_b.field("id");
	}
}

I'll give this a try.
Are you suggesting to use Modules and inline cxxfunction() alone, and not through Attributes? Or are you suggesting to use the package skeleton generator on the module (section 3.2 of Rcpp-module.pdf)?

The reason I have chosen the Attributes route vs Modules alone is:
	1) I have done the Rcpp implementation for a person who is not familiar with C++, so would like to keep a R Reference Class version of the code side by side in the source file (using Attributes supported /*** R {R code} */), so they can do their research work/updates in R and later translate the changes to C++ for performance
	2) There are global initialisation tasks that are just simpler from R (loading data files), which can be run by default on sourceCpp() invocation by placing them in /*** R */ comments, and having them calling a simple C++ function in the same source file, exposed via //[[Rcpp:export]], which is used to dump their results into the C++ environment.

So "simpler" might only be simpler for the toy example I've provided, not the real code. In any case, I'll start trying some of your suggestions out, and let you know how I go.

Cheers,
Luke.
#
This should be:

namespace Rcpp {
	template <> B as( SEXP );
}

#include <Rcpp.h>

template <> B Rcpp::as( SEXP b ){
    Rcpp::Reference in_b(b);
    return B(wrap<int>(in_b.field("id")));
}

Which I have tried, but I still get the same error. Will follow up on Dirk's other suggestions.
#
Hi Luke,
On 22 August 2013 at 00:30, Luke.Domanski at csiro.au wrote:
| Thanks for your reply Dirk,
| 
| > 
| > "Should automatically use available" wrappers/bindings.
| > 
| 
| Okay.. is it more correct to say "Should use available wrapper to automatically generate bindings"?
| 
| > Someone still has to provide the basic as<>() and wrap() code. For
| > common types we have done.  For custom types you have to do it.
| 
| Is the constructor B::B(SEXP) I implemented not already the implementation of as<B>(), as per described in section 3.1 "Intrusive extension" of Rcpp-extending?

Fair point. I may have missed that.
 
| "As part of its template meta programming dispatch logic, Rcpp::as will attempt to use the constructor of the target class taking a SEXP."
| 
| Do you think instead or in addition I should be using "Non intrusive extension" as described in section 3.2 e.g:
| 
| namespace Rcpp {
| 	template <> B as( SEXP ){
| 		Rcpp::Reference in_b(b);
| 		id=in_b.field("id");
| 	}
| }
| 
| I'll give this a try.
|
| >
| > 
| > I would try something simpler.  Rcpp Modules work well with packages,
| > so maybe try that first.
| > 
| 
| Are you suggesting to use Modules and inline cxxfunction() alone, and not through Attributes? Or are you suggesting to use the package skeleton generator on the module (section 3.2 of Rcpp-module.pdf)?

In my experience packages are best.
 
| The reason I have chosen the Attributes route vs Modules alone is:
| 	1) I have done the Rcpp implementation for a person who is not familiar with C++, so would like to keep a R Reference Class version of the code side by side in the source file (using Attributes supported /*** R {R code} */), so they can do their research work/updates in R and later translate the changes to C++ for performance

I think that is orthogonal to how you build the package.

| 	2) There are global initialisation tasks that are just simpler from R (loading data files), which can be run by default on sourceCpp() invocation by placing them in /*** R */ comments, and having them calling a simple C++ function in the same source file, exposed via //[[Rcpp:export]], which is used to dump their results into the C++ environment.

A package can do them at load time.

Dirk
 
| So "simpler" might only be simpler for the toy example I've provided, not the real code. In any case, I'll start trying some of your suggestions out, and let you know how I go.
| 
| Cheers,
| Luke.
| 
|
#
Hello,

The compiler tells you that :

Library/Frameworks/R.framework/Versions/3.0/Resources/library/Rcpp/include/Rcpp/internal/export.h:90: 
error: no matching function for call to 
?export_range__dispatch(SEXPREC*&, __gnu_cxx::__normal_iterator<B*, 
std::vector<B, std::allocator<B> > >&, Rcpp::traits::r_type_generic_tag)?

The important thing to see here is "r_type_generic_tag"


We currently only have versions of export_range__dispatch for these:

-- strings:

template <typename InputIterator, typename value_type>
void export_range__dispatch( SEXP x, InputIterator first, 
::Rcpp::traits::r_type_string_tag )

-- primitive types (double, int, ...):

template <typename InputIterator, typename value_type>
void export_range__dispatch( SEXP x, InputIterator first, 
::Rcpp::traits::r_type_primitive_tag )
		
So we need one for the r_type_generic_tag :

template <typename InputIterator, typename value_type>
void export_range__dispatch( SEXP x, InputIterator first, 
::Rcpp::traits::r_type_generic_tag )


I just added it in svn. So now your code almost compiles. I did get a

Symbol not found: __ZN1AI1BEC1ESt6vectorIS0_SaIS0_EE

which is:

$ c++filt __ZN1AI1BEC1ESt6vectorIS0_SaIS0_EE
A<B>::A(std::vector<B, std::allocator<B> >)

which I can quickly correct by implementing the constructor:

A( std::vector<T> in_vec ) : vec_of_T(in_vec){}


Then I can do this:

# Reference Class of B
B_R <- setRefClass( "B_R",
     fields = list(id="numeric")
)
b1 <- new( "B_R", id = 1 )
b2 <- new( "B_R", id = 1 )
a <- new( A, list(b1,b2) )


Romain


Le 22/08/13 01:21, Luke.Domanski at csiro.au a ?crit :

  
    
#
On 22 August 2013 at 08:21, Romain Francois wrote:
| Then I can do this:
| 
| # Reference Class of B
| B_R <- setRefClass( "B_R",
|      fields = list(id="numeric")
| )
| b1 <- new( "B_R", id = 1 )
| b2 <- new( "B_R", id = 1 )
| a <- new( A, list(b1,b2) )

Beautiful. Thanks for putting that in.

Dirk