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