Separating C++ Templates Into h and cpp files

C++ is known for separating classes into .h and .cpp files or header and source files respectively. A variety of reasons and motivations justify this approach. Among them are first and foremost the idea that C++ compilers need to know what to expect ahead of time in order to link properly. Another useful idea behind this is that a developer can separate their declaration from their definition and hide the implementation details.

Say for example that you have a super fancy proprietary compression or encryption algorithm, you can hide the implementation details in the .cpp file while still providing the API interface to use this CompressionWidget class.

//CompressionWidget.h class file
class CompressionWidget{

private:
   //... any private variables go here
public:
   void Compress(const char *sourceFilePath, 
                 const char *destinationFilePath);
   void Decompress(const char *sourceFilePath,
                   const char *destinationFilePath); 

};
//CompressionWidget.cpp source file
void doCompress(const char* sourceFilePath, 
                const char* destinationFilePath){
      //implementation details here
}

void doDecompress(const char* sourceFilePath, 
                const char* destinationFilePath){
      //implementation details here
}

void Compress(const char *sourceFilePath, 
                 const char *destinationFilePath){
      //do compress
      doCompresss(sourceFilePath, destinationFilePath);
}

void Decompress(const char *sourceFilePath, 
                 const char *destinationFilePath){
      //do decompress
      doDecompresss(sourceFilePath, destinationFilePath);
}

As you can see in the code above you can hide the details in the cpp file. In fact you can hide even more by hiding the helper functions that help you compress. Instead of even hinting at which other dependencies you may have hide a lot in the cpp file.

But what about separating templates?

In C++ you can create template classes. If you are more familiar with a newer language like Java or C# you may know these as generics (similar idea but possibly not exactly the same). The idea is that you create one class that can work with any data type. Let’s say for example you ave a data structure class like a Stack and you want to separate the declaration from the implementation. This can get pretty tricky with templates.

The reason it gets tricky is because a template is not really source code. The source generation occurs when you actually declare the instance of the class.

template <typename T>
class Stack{

public: 
    void Push(T item){ ... }
    T Pop(){ ... }
};
int main(int argc, char *argv){
   //This causes the compiler to compile the Stack for doubles
   Stack<double> stack;   

}
//This or something like this is what the compiler creates
class StackDouble{

public:
    void Push(double item){...}
    double Pop();

};

So… if you try to separate the Stack class into separate h and cpp files you will get a series of errors that will have you pulling your hair. In the example above I declared the the Stack class with the member functions inline. You can still separate them but they must be in the same class. You cannot put the implemenation in a C# file.

If you put the implentation in a Stack.cpp file you will run into compiler issues.

The Solution

One way to get around that problem and this is something that I saw a student do before is to put include the .cpp file at the end of the .h file.


template <typename T>
class Stack{

public: 
    void Push(T item){ ... }
    T Pop(){ ... }
};

#include "Stack.cpp"

The approach works and if you are using a light code editor you probably won’t have much problems. However, you will run into problems because a compiler may have issues with this approach because it will try to compile the Stack.cpp file and not find definitions from the .h file. Another problem that you may run into is that when you run the compile command the compiler will try to compile the .cpp file when in fact it should only compile the .h file.

$ g++ *.cpp -o program.exe

Recently I discovered a solution that works quite well. So instead of a .cpp file for your implementation, use a .tpp file.

//Stack.h
#ifndef STACK_H
#define STACK_H

template<typename T>
class Stack
{
private:
    T data[20];
    int topIndex;
public:
    Stack(/* args */);
    ~Stack();
    void push(T entry);
    T pop();
    T peek();
    T empty();
    T clear();
    int size();
};

template <typename T>
Stack<T>::Stack(/* args */)
{
    topIndex = -1;
}

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


#include "Stack.tpp"

#endif // !STACK_H
//Stack.tpp
template <typename T>
void Stack<T>::push(T entry){

  if(topIndex + 1 < 20){
      data[++topIndex] = entry;
  }
}

template <typename T>
T Stack<T>::pop(){
   if(topIndex >= 0){
       return data[topIndex--];
   }

    //throw exception here
   T t;

   return t;
}

template <typename T>
T Stack<T>::peek(){

   return data[topIndex]
}

template <typename T>
T Stack<T>::empty(){
    return topIndex < 0;
}

template<typename T>
T Stack<T>::clear(){
    topIndex = -1;
}

template <typename T>
int Stack<T>::size(){
    return topIndex + 1;
}
//MyApp.cpp
#include <iostream>
#include "Stack.h"

using namespace std;

int main(int argc, char *argv[]){

     Stack<double> stackD;
     Stack<int> stackI;

     stackD.push(1);
     stackD.push(2);

     cout << stackD.pop() << endl;
     cout << stackD.pop() << endl;
     
     stackI.push(3);
     stackI.push(4);

     cout << stackI.pop() << endl;
     cout << stackI.pop() << endl;
    
    return 0;
}

The solution above allows you to separate declaration from implementation. Does it fully allow you to hide the details? probably not since you will likely need to provide the .tpp file. If you have proprietary code in templates, there is not much you can do about it.

About the only thing you get out of this approach is that you are able to keep your code a bit cleaner. So, likely you would not want to implement proprietary valuable IP code in templates.

Summary

The long story short with this exercise is that you are able to separate implementation from declaration for templates. It does not solve the problem of hiding implementation details. The biggest take away is that you have a better understanding of templates and while you do not get the true benefits of separating declaration from definition, you do now know how to properly separate them if you need to. Like anything else, knowledge is power and at least you won’t be pulling your hair like I did when faced with this problem.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: