2

I have a template class that has a big member function in generic form, so it is not very easy to read it through. I decide to move this function outside of the class body, and implement it in a ".cpp" file that with same name as the ".hpp", but I can't pass the compiling. If I implement it in a specialized form rather than a generic form, it can be compiled/linked, even though it be saved in the "*.cpp" file too.

The codes is following:

ClassC.hpp:

#pragma once
template <typename T>
class ClassC {
public:
   ClassC( T* p ) : d( p ) {};
   void show();
private:
   T* d;
};

ClassC.cpp

#include <iostream>
#include "ClassC.hpp"
#include "ClassD.hpp"
using namespace std;

// this is a specialized version, and can be compiled/linked.
template <>
void ClassC<ClassD>::show() {
   cout << "This is a specialized ClassC." << endl;
};

// this is my generic version, and can not be compiled.
template <typename T>
void ClassC::show() {
     cout << "This is a generic ClassC." << endl;
};
/* */

ClassD.hpp

#pragma once
#include "ClassC.hpp"
class ClassD {
public:
   ClassD(): c( this ) {};
   void show();
private:
   ClassC<ClassD> c;
};

ClassD.cpp

#include <iostream>
#include "ClassD.hpp"
using namespace std;
void ClassD::show() {
   c.show();
   cout << "This is ClassD" << endl;
};

main.cpp

#include "ClassD.hpp"
int main() {
   ClassD d;
   d.show();
   return 0;
};
Leon
  • 1,489
  • 1
  • 12
  • 31
  • 2
    On the right side there's a list of related questions. Take a look through those, especially the one named [Why can templates only be implemented in the header file?](https://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file?rq=1). – Some programmer dude Jan 30 '19 at 12:45
  • And if you want help with your specific problem, then you need to tell us what the specific problem is. What errors do you get? If you can't be specific, then we can't give specific answers. Also please read about [how to ask good questions](http://stackoverflow.com/help/how-to-ask), as well as [this question checklist](https://codeblog.jonskeet.uk/2012/11/24/stack-overflow-question-checklist/). – Some programmer dude Jan 30 '19 at 12:46
  • When I add the generic version, I commented the specialized. – Leon Jan 30 '19 at 12:48
  • path/of/the/ClassC.cpp:16:6: error: ‘template class ClassC’ used without template parameters – Leon Jan 30 '19 at 12:49

2 Answers2

3

There are a couple of ways to fix this problem:

  • Explicit Instantiation
  • The Inclusion Model
  • The Seperation Model

Explicit Instantiation Works similar to your example of template specialization:

template my_class<size_t>::my_class();

Explicitly instantiates the constructor of my_class<T> for type size_t.

The Inclusion Model The code is either written inside the .h file, a very common approach to deal with this problem, or we include the definitions of a template in the header file that declares that template, so: #include "my_file.cpp".

The Seperation Model Use the keyword export. However, I have almost never used this, as it performs quite slowly.

export template <typename T>
struct C {};
Lourens Dijkstra
  • 420
  • 2
  • 11
  • Thanks a lot! I'm going to use the first solution your mentioned, because I'm worry about that the second one could probably lead to some "symbol redefining" issues, if the "my_file.cpp" need to be included in more than one place. As for the third one, it looks like that the keyword "export" has be marked deprecated in most modern compiler and the latest c++ standard. If I have comprehended it correctly, the word "Instantiation" in the first solution may be understood as "Specialization". Am I right? Not for revise, just for understanding. – Leon Jan 30 '19 at 13:43
  • The difference is described in this question: https://stackoverflow.com/questions/3914642/difference-between-instantiation-and-specialization-in-c-templates – Lourens Dijkstra Jan 30 '19 at 13:51
2

You have e.g.

template <typename T>
void ClassC::show() {
     cout << "This is a generic ClassC." << endl;
};

The problem here is that there is no class named ClassC, you only have a template with that name. To get a full class you need ClassC<T>:

template <typename T>
void ClassC<T>::show() {
     cout << "This is a generic ClassC." << endl;
};

Like the error message says, you need to include the template parameters.

And of course don't forget to read Why can templates only be implemented in the header file? as that will answer what might be your next question.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621