Linker error: undefined reference to methods of template class

Hello,

I just introduced templates into my classes and getting the following linker error (on linux):
Linking CXX executable main
CMakeFiles/main.dir/main.cc.o: In function `main':
/media/sf_Eclipse_Deal_II_sharedFolder/Eclipse_Win_workspace/ChannelFlowWithFlatPlateSource/main.cc:46: undefined reference to `ChannelFlow<dealii::Vector<double>, dealii::SparseMatrix<double> >::ChannelFlow(cmdParametersStruct)'
/media/sf_Eclipse_Deal_II_sharedFolder/Eclipse_Win_workspace/ChannelFlowWithFlatPlateSource/main.cc:48: undefined reference to `ChannelFlow<dealii::Vector<double>, dealii::SparseMatrix<double> >::run()'
CMakeFiles/main.dir/main.cc.o: In function `ChannelFlow<dealii::Vector<double>, dealii::SparseMatrix<double> >::~ChannelFlow()':
/media/sf_Eclipse_Deal_II_sharedFolder/Eclipse_Win_workspace/ChannelFlowWithFlatPlateSource/src/ChannelFlow.h:29: undefined reference to `BaseSolver<dealii::Vector<double>, dealii::SparseMatrix<double> >::~BaseSolver()'
CMakeFiles/main.dir/main.cc.o: In function `~ChannelFlow':
/media/sf_Eclipse_Deal_II_sharedFolder/Eclipse_Win_workspace/ChannelFlowWithFlatPlateSource/src/ChannelFlow.h:29: undefined reference to `BaseSolver<dealii::Vector<double>, dealii::SparseMatrix<double> >::~BaseSolver()'
collect2: error: ld returned 1 exit status


the only code from main.cc that uses ChannelFlow:
ChannelFlow<MyVectorType, SparseMatrixType> channelFlowProblem(cmdParameters);
channelFlowProblem.run();

Before templates it was linking and running well.
ChannelFlow.h file:
template <class VectorType, class SparseMatrixT>
class ChannelFlow : public BaseSolver<VectorType, SparseMatrixT>
{

public:
ChannelFlow (cmdParametersStruct cmdParameters);

inline ~ChannelFlow(){};
void run ();
and lots of other code, which I believe is irrelevant

constructor in ChannelFlow.cpp is defined as:
ChannelFlow<VectorType, SparseMatrixT>::ChannelFlow(cmdParametersStruct cmdParameters)
{
skipped
}

BaseSolver class:
template <class VectorType, class SparseMatrixT>
class BaseSolver{ //abstract class
BaseSolver();
virtual ~BaseSolver();
skipped code
}

template <class VectorType, class SparseMatrixT> //TODO: split into 2 constructors depending on VectorType and SparseMatrixT classes!
BaseSolver<VectorType, SparseMatrixT>::BaseSolver(){
skipped code
}

template <class VectorType, class SparseMatrixT>
BaseSolver<VectorType, SparseMatrixT>::~BaseSolver(){}; - nothing skipped, destructor is empty

Please help me to troubleshoot this. Thanks!
Thank you! I added template class instantiation to the end of cpp files. The linker still gives errors I think because I also have template methods inside same template classes:

1
2
3
4
5
6
7
[ 66%] Building CXX object CMakeFiles/main.dir/src/one_pass_logic/doTimeStepOneRunAver.cpp.o
Linking CXX executable main
CMakeFiles/main.dir/src/one_pass_logic/doTimeStepOneRunAver.cpp.o: In function `ChannelFlow<dealii::TrilinosWrappers::MPI::Vector, dealii::TrilinosWrappers::SparseMatrix>::doTimeStepOneRunAver()':
/media/sf_Eclipse_Deal_II_sharedFolder/Eclipse_Win_workspace/ChannelFlowWithFlatPlateSource/src/one_pass_logic/doTimeStepOneRunAver.cpp:57: undefined reference to `Drag<dealii::Vector<double>, dealii::SparseMatrix<double> >::Drag<dealii::TrilinosWrappers::MPI::Vector, dealii::TrilinosWrappers::SparseMatrix>(ChannelFlow<dealii::TrilinosWrappers::MPI::Vector, dealii::TrilinosWrappers::SparseMatrix>&, cmdParametersStruct)'
/media/sf_Eclipse_Deal_II_sharedFolder/Eclipse_Win_workspace/ChannelFlowWithFlatPlateSource/src/one_pass_logic/doTimeStepOneRunAver.cpp:104: undefined reference to `double Drag<dealii::Vector<double>, dealii::SparseMatrix<double> >::computeDrag<dealii::TrilinosWrappers::MPI::Vector>(dealii::TrilinosWrappers::MPI::Vector&, dealii::TrilinosWrappers::MPI::Vector&)'
collect2: error: ld returned 1 exit status
make[6]: *** [main] Error 1 


When I add template method instanciation like this :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
typedef dealii::Vector<double> dealVector ;
typedef dealii::SparseMatrix<double> dealMatr;
typedef dealii::TrilinosWrappers::MPI::Vector TrilVec;
typedef dealii::TrilinosWrappers::SparseMatrix TrilMatrix;
typedef Drag< dealii::Vector<double>, dealii::SparseMatrix<double> > DragWithRegularClasses;

template class Drag<dealVector, dealMatr >;
template double Drag<dealii::Vector<double>, dealii::SparseMatrix<double>>::computeDrag<dealii::Vector<double>>( dealii::Vector<double>, dealii::Vector<double>);

template Drag<dealVector, dealMatr >::Drag(TrilVec, TrilMatrix, cmdParametersStruct);
template Drag<dealVector, dealMatr >::Drag(dealVector, dealMatr, cmdParametersStruct);

template Drag<dealVector, dealMatr >::Drag<TrilVec, TrilMatrix>(TrilVec, TrilMatrix, cmdParametersStruct);
template Drag<dealVector, dealMatr >::Drag< dealVector, dealMatr >(dealVector, dealMatr, cmdParametersStruct);


I get following errors:
1
2
3
4
5
6
7
8
9
10

/media/sf_Eclipse_Deal_II_sharedFolder/Eclipse_Win_workspace/ChannelFlowWithFlatPlateSource/src/drag/Drag.cpp:223:17: error: template-id �computeDrag<dealii::Vector<double> >’ for �double Drag<dealii::Vector<double>, dealii::SparseMatrix<double> >::computeDrag(dealii::Vector<double>, dealii::Vector<double>)’ does not match any template declaration
 template double Drag<dealii::Vector<double>, dealii::SparseMatrix<double>>::computeDrag<dealii::Vector<double>>( dealii::Vector<double>, dealii::Vector<double>);
                 ^
/media/sf_Eclipse_Deal_II_sharedFolder/Eclipse_Win_workspace/ChannelFlowWithFlatPlateSource/src/drag/Drag.cpp:225:10: error: template-id �Drag<>’ for �Drag<dealii::Vector<double>, dealii::SparseMatrix<double> >::Drag(TrilVec, TrilMatrix, cmdParametersStruct)’ does not match any template declaration
 template Drag<dealVector, dealMatr >::Drag(TrilVec, TrilMatrix, cmdParametersStruct);
          ^
/media/sf_Eclipse_Deal_II_sharedFolder/Eclipse_Win_workspace/ChannelFlowWithFlatPlateSource/src/drag/Drag.cpp:226:10: error: template-id �Drag<>’ for �Drag<dealii::Vector<double>, dealii::SparseMatrix<double> >::Drag(dealVector, dealMatr, cmdParametersStruct)’ does not match any template declaration
 template Drag<dealVector, dealMatr >::Drag(dealVector, dealMatr, cmdParametersStruct);
          ^


Here is Drag class code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
template <class VectorType, class SparseMatrixT>
class Drag : public BaseSolver<VectorType, SparseMatrixT> {
public:
	ChannelFlow<VectorType, SparseMatrixT>& channelFlowRef;
	template  <class VectorType2, class SparseMatrixT2> //function template parameters
	Drag(ChannelFlow<VectorType2, SparseMatrixT2>& channelFlow, cmdParametersStruct cmdParameters);
  template<class VectorType2>
  double  computeDrag(VectorType2& solutionNext, VectorType2& solutionCur); //computeDrag function

skipped code
}

template <class VectorType, class SparseMatrixT>
template  <class VectorType2, class SparseMatrixT2> //function template parameters
Drag<VectorType, SparseMatrixT>::Drag(ChannelFlow<VectorType2, SparseMatrixT2>& channelFlow, cmdParametersStruct cmdParameters):
	BaseSolver<VectorType, SparseMatrixT>(cmdParameters){
skipped }

template <class VectorType, class SparseMatrixT> //Drag class template parameters
template  <class VectorType2> //function template parameters
double  Drag<VectorType, SparseMatrixT>::computeDrag(VectorType2& solutionNext, VectorType2& solutionCur){ 
skipped }


Is it possible to instanciate explicitly template method from template class at all?
I tried google and different syntaxes, for example from this page
http://stackoverflow.com/questions/8640390/c-template-function-inside-template-class

Some people write that instantiation of template class must be after instantiation of template methods. Is this true?
I tried both ways.
Last edited on
Thank you for your help, but I really don't have time to write a testcase as I am under strict time deadline. I believe any code with template class containing template method (just put its implementation into separate file from class definition and don't include implementation file in header file or anywhere else) will give the above error.
I resolved it by putting all the implementation for the above class from cpp to header file. Don't like such solution.
So the question is still there: how to instantiate a template method of template class?
Is it possible at all?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//foo.cpp
#include "asdf.h"

int main(){
	foo<int> asdf;
	asdf.bar(3.14);
}

//asdf.h
#ifndef ASDF_H
#define ASDF_H 

template <class T>
class foo{
public:
	template <class U>
	void bar(U x);
};

#endif

//asdf.cpp
#include <iostream>
#include "asdf.h"

template <class T>
template <class U>
void foo<T>::bar(U x){
	std::cout << "foo::bar " << x << '\n';
}

template void foo<int>::bar(double);


$ g++ -c foo.cpp asdf.cpp
$ nm -C foo.o
                 U void foo<int>::bar<double>(double)
0000000000000000 T main
$ nm -C asdf.o
0000000000000000 W void foo<int>::bar<double>(double)
$ g++ foo.o asdf.o -o program.bin

So you need instantiate only template method?
I was instantiating template class itself as well. How to instantiate if you have 2 or more template methods?
instantiating the template class will generate the code for all non-template methods.
apart you'll need to instantiate each template method for every type that you want to use.
Topic archived. No new replies allowed.