undefined reference to template function error

Im getting undefined reference error while using templates functions.
I think is because im missing something on my header file. Can someone point me to
the right direction.
thanks.

this is the error

1
2
3
4
5
6
7
8
9
10
11
12
g++    -c -o statsTypeImp.o statsTypeImp.cpp
g++ -Wall -pedantic -Wextra -std=c++11 -o main main.o statsTypeImp.o
main.o: In function `main':
main.cpp:(.text+0xc2): undefined reference to `statsType<int>::statsType()'
main.cpp:(.text+0x166): undefined reference to `statsType<int>::setFileName(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)'
main.cpp:(.text+0x18d): undefined reference to `statsType<int>::readDataFile()'
main.cpp:(.text+0x1c1): undefined reference to `statsType<int>::printDataSet() const'
main.cpp:(.text+0x1cd): undefined reference to `statsType<int>::~statsType()'
main.cpp:(.text+0x235): undefined reference to `statsType<int>::~statsType()'
collect2: error: ld returned 1 exit status
makefile:13: recipe for target 'main' failed
make: *** [main] Error 1 


this is the main file

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
33
34
35
36
  #include <cstdlib>
#include <iostream>
#include <cmath>
#include <iomanip>
#include <string>

#include "statsType.h"

using namespace std;


// #######################################################################

int main()
{
// **********************************************************
//  Initalizations and headers

	string	bars, stars;
	bars.append(50,'-');
	stars.append(70,'=');

	cout << endl << "Assignment #7 - Statistics Testing" << endl << endl;

statsType <int> set1;
	int	min1, max1, med1, sum1, ave1;
	int	sStd1, pStd1, sk1, fp1;

	cout << stars << endl;
	cout << "Data Set 1 - Integers" << endl << endl;

	set1.setFileName("dataFile1.txt");
	set1.readDataFile();

	cout << "Data Set 1 -> Unsorted:" << endl;
	set1.printDataSet();




this is the imp file

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119

#include <cstdlib>
#include <iostream>
#include <cmath>
#include <iomanip>
#include <string>
#include <fstream>

#include "statsType.h"
using namespace std;
template <class myType>

/*set the filename to the empty string, the setSize to 0, and dataSet pointer to nullptr.*/
statsType<myType>::statsType() {
    fileName = "";
    setSize = 0;
    dataSet = nullptr;
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*accept a filename, set setSize to 0 and dataSet to nullptr.*/
template <class myType>
statsType<myType>::statsType(string fileName){

    this->fileName = fileName;
    setSize = 0;
    dataSet = nullptr;
    setFileName(fileName);

    //setFileName(); ////////////////////////////////////////////////////////////////////////////////////////////////////////
}

/*destructor of the class ,deletes the myType array, set the pointer to nullptr,
 the setSize to 0, and the file name to the empty string.*/
 template <class myType>
statsType<myType>::~statsType(){


    dataSet = nullptr;
    setSize = 0;
    fileName = "";
    delete [] dataSet;
}

/*return the current filename.*/
 template <class myType>
string statsType<myType>::getFileName()const{
    return fileName;
}

/*set the class variable for the filename to the passed value.*/
 template <class myType>
bool statsType<myType>::setFileName(string fileName){

    if(fileName.size() > 4 && (fileName.substr(fileName.size() - 3) == "dat" || fileName.substr(fileName.size() - 3) == "txt") /*||(access(fileName.c_st r(), F_OK))*/) {

        this->fileName= fileName;

        return true;


        }

    else {

        cout << "File does not exist"<< endl;

        return false;

    }
}


/*prompt for and read a filename from the user*/
 template <class myType>
bool statsType<myType>::readFileName() {

    cout << "Enter Input File Name: none ";
    cin >>fileName;

    while (!(fileName.substr(fileName.size() - 3) == "dat" || fileName.substr(fileName.size() - 3) == "txt")){

        cout << "Error, invalid file name";
        cin >>fileName;
        }

    setFileName(fileName);
}

template <class myType>
bool statsType<myType>::readDataFile(){

    ifstream inFile ("dataFile1.txt");
    inFile.ignore(1000, '\n');
    inFile.ignore(1000, '\n');
    inFile.ignore(1000, '\n');
    inFile.ignore(1000, '\n');
    inFile >> setSize;
    dataSet = new myType[setSize];

    for(int i =0; i < setSize; i++) {
        inFile >> dataSet[i];
    }

    delete [] dataSet;
    inFile.close();

}

template <class myType>
void statsType<myType>::printDataSet() const{ //printDataSet() function should print data items of type myType with nine (9) values per line.

    for (int i = 0; i < setSize; i++) {
        cout << dataSet [i] << " ";
    }
    cout<<endl;
    //cout << siz << endl;
}





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

#ifndef STATSTYPE_H_INCLUDED
#define STATSTYPE_H_INCLUDED
using namespace std;

template <class myType>
class statsType{

    int setSize;
    myType *dataSet;
    string fileName;

public:

    statsType(); //set the filename to the empty string, the setSize to 0, and dataSet pointer to nullptr.

    statsType(string); //accept a filename, set setSize to 0 and dataSet to nullptr.
    ~statsType(); //setSize to 0, and the file name to the empty string.
    string getFileName() const; //return the current filename.
    bool setFileName(string); //set the class variable for the filename to the passed value.

    bool readFileName(); //prompt for and read a filename from the user
    bool readDataFile(); //read the data file (from fileName
    myType getElement(int) const; //return the data item of type myType at the location of the passed index (integer).
   
};
Last edited on
Just looking at a glance, templated classes/functions cannot be separated as a header + implementation file in this way.

The easiest fix would be to just define all the templated defintions in your header file and not have a corresponding imp file. There are other creative ways to still allow pseudo-separation*, but it isn't necessary.

The ISO C++ FAQ has a section about this: https://isocpp.org/wiki/faq/templates#templates-defn-vs-decl

*also discussed here: https://stackoverflow.com/a/495056/8690169
Last edited on
Thank you, as soon as i moved everything to the header file, it worked
Topic archived. No new replies allowed.