0

I have a templated class named DataHandler

#ifndef DATAHANDLER_H
#define DATAHANDLER_H
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include <set>
#include "constants.h"

template <typename T>
using Car = std::pair< T, T>;

template <typename T>
using SparseMatrix = std::vector< Car<T> >;

template <class T>
class DataHandler
{

    public:
        // initializes a new DataHandler only if none has been created,
        // otherwise return the living instance
        static DataHandler<T>* getInstance()
        {
            if(!dataHandler)
                dataHandler = new DataHandler();
            return dataHandler;
        }

        void readFile();

        SparseMatrix<T>* getSparseBlue(){ return &sparseBlue; }
        SparseMatrix<T>* getSparseRed(){ return &sparseRed; }
        virtual ~DataHandler();

    private:
        // static DataHandler to ensure only one instance can be created
        static DataHandler<T> *dataHandler;

        // private constructor to use DataHandler as a Singleton
        DataHandler();

        int numElem = 0;
        int m_rows, m_cols = -1;


#endif // DATAHANDLER_H

The source file is:

#include "data_handler.h"
#include <fstream>
#include <algorithm>
#include <omp.h>
#include <chrono>

using namespace std;
using namespace constants;

// Global static pointer used to ensure a single instance of the class.
template<typename T>
DataHandler<T>* DataHandler<T>::dataHandler = NULL;

template<typename T>
DataHandler<T>::DataHandler()
{
//ctor
}

template<typename T>
DataHandler<T>::~DataHandler()
{
//dtor
}

template<typename T>
void DataHandler<T>::readFile()
{
   // do some stuff
}

// Instantiation of relevant templates
template class DataHandler<unsigned char>;
template class DataHandler<unsigned short int>;

In the last two lines I instantiate the templates which I define in main.cpp:

#include <iostream>
#include <chrono>
#include <fstream>
#include <algorithm>

#include "data_handler.h"
#include "dense_traffic_handler.h"
#include "sparse_traffic_handler.h"
#include "constants.h"

using namespace std;   

// Check the number of rows/cols to choose between char or short int for the sparse case
bool matrixIsSmall()
{    
    return true;
}
void integerCase()
{
    typedef unsigned char T;
    DataHandler<T> *dh = DataHandler<T>::getInstance();
    dh->readFile();

    DenseTrafficHandler dth(dh);    // ****** ERROR HERE *****
}

void charCase()
{
    typedef unsigned char T;
    DataHandler<T> *dh = DataHandler<T>::getInstance();
    dh->readFile();

    DenseTrafficHandler dth(dh);    // ****** ERROR HERE *****
    SparseTrafficHandler<T> sth;

    set<unsigned short int> step = dh->getstep();

    int currentStep = 0;
    set<unsigned short int>::const_iterator stepToSave = step.begin();
}

int main(int argc, char *argv[])
{
    if(matrixIsSmall())
        charCase();
    else
        integerCase();

    return 0;
}

Compiler gives me an error: undefined reference to DenseTrafficHandler::DenseTrafficHandler<unsigned short>(DataHandler<unsigned short>*)

DenseTrafficHandler header is like that:

#ifndef TRAFFICHANDLER_H
#define TRAFFICHANDLER_H

#include "constants.h"
#include "data_handler.h"

class DenseTrafficHandler
{
    public:
        template<typename T>
        DenseTrafficHandler(DataHandler<T> *dh);
        virtual ~DenseTrafficHandler();
    private:
        int m_cols, m_rows;
        char* data;
        char ** dense = NULL;
};

#endif // TRAFFICHANDLER_H

DenseTrafficHandler source is:

#include "dense_traffic_handler.h"

using namespace std;
using namespace constants;

template <typename T>
DenseTrafficHandler::DenseTrafficHandler(DataHandler<T> *datah)
{
    DataHandler<T> *dh = datah;
    dense = dh->getDense();
    m_rows = dh->getm_rows();
    m_cols = dh->getm_cols();
}
DenseTrafficHandler::~DenseTrafficHandler()
{
    //dtor
}

So I have two questions:

  1. Why do I receive this error and how can I manage it?
  2. Is there a way in DataHandler source to not specify template <typename T> DataHandler<T>::functionName() for every function? (I mean something like using namespace Datahandler<T>)
rh0x
  • 1,066
  • 1
  • 13
  • 33

1 Answers1

2
  1. You receive this error because compiler did not generate the code for this template type. One of solutions is to tell the compiler to do this explicitly by template instantiation:

    add to your DenseTrafficHandler.cpp:

    template class DenseTrafficHandler<unsigned short>;
    
  2. Yes, just implement it in the header file. Reading more about it here.

Community
  • 1
  • 1
VP.
  • 15,509
  • 17
  • 91
  • 161
  • 1
    #2 is yes only if the function are declared in the class body. If the OP still wants to define the functions outside the class body he will still have to use `template DataHandler::functionName()` for every function. – NathanOliver Jan 25 '16 at 13:15
  • Thank you, but since DenseTrafficHandler is not a template class I cannot use this solution (and I don't want to make it a template class). I solved it overriding the constructor, specifying the two possible types (char and short). In fact, I need to use the template class DataHandler only in the constructor of DenseTrafficHandler, so this solution is better for my purposes. – rh0x Jan 25 '16 at 17:42
  • @rh0x Oops, just found out that it is not a template class but only a template constructor, sorry, I missed that somehow. Yes, you had to make the specializations for different types, so you did it right. I'll update the answer. – VP. Jan 25 '16 at 17:46