0

I have the following three files in the same directory:

citysim.cpp

#include "utils.h"
using namespace std;

int main()
{
    City *c;
    c = new City();
    Graph<City *> g;
    g.addVertex(c);
}

utils.h

#include <iostream>
#include <map>
#include <vector>
using namespace std;

class City {
    public:
        City() {}
    private:
        string name;
};

template <typename Tkey>
class Graph {
    public:
        Graph() {}
        void addVertex(Tkey);
    private:
        vector<Tkey> v;
        vector< vector<int> > e;
        map<Tkey, int> key_map;
};

utils.cpp

#include "utils.h"

template <typename Tkey>
void Graph<Tkey>::addVertex(Tkey vertex)
{
    v.push_back(vertex);
}

And I am really perplexed as to why the following compilation sequence produces the result indicated:

test> g++ -c citysim.cpp
test> g++ -c utils.cpp
test> g++ -o citysim citysim.o utils.o
citysim.o: In function `main':
citysim.cpp:(.text+0x4a): undefined reference to `Graph<City*>::addVertex(City*)'
collect2: ld returned 1 exit status

Any ideas or insights are appreciated!

user434462
  • 49
  • 7
  • possible duplicate of [Why am I getting a Linker error with template function pointer?](http://stackoverflow.com/questions/4763216/why-am-i-getting-a-linker-error-with-template-function-pointer) – 6502 Mar 26 '12 at 19:53
  • Please don't use `using namespace std;` in a header file. – quamrana Mar 26 '12 at 19:56
  • Okay, why not? Wouldn't I have to prefix std:: to string, vector, map, etc.? Thanks, I would really like to know. – user434462 Mar 26 '12 at 21:47
  • @user434462: Yes, that's right, you'll have to prefix std:: in your headers. See: http://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-a-bad-practice-in-c – quamrana Mar 27 '12 at 12:50

2 Answers2

1

Define everything of your templated class in your header file, not in a cpp file. Instead of having your utils.cpp have everything like this in your header file:

template <typename Tkey>
class Graph {
public:
    Graph() {}
    void addVertex(Tkey vertex)
    {
         v.push_back(vertex);
    }
private:
    vector<Tkey> v;
    vector< vector<int> > e;
    map<Tkey, int> key_map;
};

Here is the related reading in the faq...

EDIT: (But you can define it later on like you did it in your cpp in the header file as well...)

niktehpui
  • 560
  • 3
  • 15
  • Ah, so a templated class declaration and its member definitions must appear in the same file. Great information, thanks! (Tried it and it worked.) – user434462 Mar 26 '12 at 20:05
  • Actually they don't have to appear in the same file, but the definition does have to appear in at least one file where the template is instantiated. So you could hide the definition in a .cpp file as long as you also instantiate it there for all types that use it in your system. – Peter Wood Mar 26 '12 at 20:37
0

Template functions must be written entirely on the header, their definitions can't go on the cpp file.

Castilho
  • 3,147
  • 16
  • 15
  • Not true, see my comment on @niktehpui's answer. – Peter Wood Mar 26 '12 at 21:49
  • Yep, know that. But instead of explaining this it's better to say the gereal rule instead of explaining that templates are evaluated at compile time and actually produce one different function for every type that's used. – Castilho Mar 26 '12 at 21:53
  • @Castilho: Not all compilers use this model for templates. Borland C++ through 5.x or so allowed one to do as the OP did. There are others. – JimR Mar 27 '12 at 05:17