0

I am writing an R-package using Rcpp. I use sourceCpp to run quick tests and check compilation. (EDIT: I encounter the same problem when building a package, see below).

I try to use a template class. I wrote a short example that reproduce my problem. Here is the header file where I define a template class myClass1 and a standard class myClass2:

test1.h

template<typename T>
class myClass1 {
public:
    T attr1;

    myClass1(T x);
    ~myClass1();
};

class myClass2 {
public:
    double attr2;

    myClass2(double x);
    ~myClass2();
};

And the corresponding source file:

test1.cpp

#include "test1.h"

template<typename T>
myClass1<T>::myClass1(T x) : attr1(x) {}

template<typename T>
myClass1<T>::~myClass1() {}

myClass2::myClass2(double x) {
    attr2 = x;
}
myClass2::~myClass2() {}

I finally define a function in Cpp to be exported in R that is just supposed to print the value of the attribute ot the object myClass2 that is an attribute of the template class myClass1.

test_to_R.cpp

#include <Rcpp.h>
#include <cstdio>
#include "test1.h"

// [[Rcpp::export]]
void test_to_R() {
    myClass1<myClass2> test(2);

    Rcpp::Rcout << test.attr1.attr2 << std::endl;
}

When I try to compile the file test_to_R.cpp with sourceCpp (all my header and source file are in the subdirectory "pkg/src"), I get the following error:

> sourceCpp("pkg/src/test_to_R.cpp")
Error in dyn.load("/tmp/RtmpgY8Tfg/sourcecpp_dd86f6c3c82/sourceCpp_7.so") : 
  unable to load shared object '/tmp/RtmpgY8Tfg/sourcecpp_dd86f6c3c82/sourceCpp_7.so':
  /tmp/RtmpgY8Tfg/sourcecpp_dd86f6c3c82/sourceCpp_7.so: undefined symbol: _ZN8myClass1I8myClass2ED1Ev

I get that there is a link problem, as it cannot find the destructor:

$ cd /tmp/RtmpgY8Tfg/sourcecpp_dd86f6c3c82
$ c++filt _ZN8myClass1I8myClass2ED1Ev
myClass1<myClass2>::~myClass1()

If I declare and define the function test_to_R in the same header/source files than the template class, it works. Do you have any idea how to set the good linking options to overcome this issue?

I work on GNU/Linux (Ubuntu 14.04) with R 3.3.0 and Rcpp 0.12.5 and I use a standard Rcpp skeleton package generated by Rcpp.package.skeleton("pkg")

Thanks in advance

EDIT

When building a package, I encounter the same issue. If a function that instantiate a class template is defined in the same header/source files as the class template, it works. However, if the class template and the Cpp to R function that instantiate it are in different files, I get the same error.

Example: I replace test1.cpp by test2.cpp in my previous example and build the package.

test2.cpp

#include <Rcpp.h>
#include <cstdio>
#include "test1.h"

template<typename T>
myClass1<T>::myClass1(T x) : attr1(x) {}

template<typename T>
myClass1<T>::~myClass1() {}

myClass2::myClass2(double x) {
    attr2 = x;
}
myClass2::~myClass2() {}

// [[Rcpp::export]]
void test_to_R() {
    myClass1<myClass2> test(2);

    Rcpp::Rcout << test.attr1.attr2 << std::endl;
}

(in this case, it works)

I check the doc as recommanded by @DirkEddelbuettel, there is an example where the template class and its instantiation are in the same header/source files, but I cannot find example where the template class are instantiated in code from an other source file as in my example.

EDIT2

As stated by @KonradRudolph, my problem was a Cpp issue (not linked to Rcpp). Template definition and implementation should be in the same file. See for instance Splitting templated C++ classes into .hpp/.cpp files--is it possible?

However, there exists a trick that allows implementing template in an other file: https://stackoverflow.com/a/9992920/5143653

Community
  • 1
  • 1
Odin
  • 633
  • 4
  • 11
  • Just use a package; if you insist on sourceCpp() see its documentation we have examples for use with template classes. Or just trust me and use it via a package. – Dirk Eddelbuettel Jun 07 '16 at 09:57
  • Ok, thanks for your answer. I am developping a package. I just use sourceCpp for quick test when writing code (and avoid full compilation at each modification). I will check the doc. – Odin Jun 07 '16 at 10:52
  • I actually edit my question because I get the same issue when building the package. – Odin Jun 07 '16 at 12:20
  • How are you building the package? – coatless Jun 07 '16 at 12:52
  • @Coatless, I tried with Rstudio and with my own script that run `compileAttribute` and `R CMD BUILD`. Both give the same outcome. – Odin Jun 07 '16 at 12:54
  • 3
    That’s a typical C++ beginners’ error that has nothing to do with R/Rcpp: you cannot put a template’s implementation into a separate cpp file, it needs to be inside the header file. Search for the topic here on Stack Overflow. – Konrad Rudolph Jun 07 '16 at 13:11
  • @KonradRudolph Thanks, I find a topic on this subject, it was effectively a Cpp problem and not Rcpp problem. – Odin Jun 07 '16 at 13:27
  • I'll change the tags. – Dirk Eddelbuettel Jun 07 '16 at 14:10

0 Answers0