Thread: Undefined Reference

  1. #1
    Registered User Russell's Avatar
    Join Date
    May 2004
    Posts
    71

    Undefined Reference

    This problem has me absolutely stumped. As far as I can tell it's an include issue, but I don't know why.

    perimosMain.cpp
    Code:
          1 #include "perimosDatabase.hpp"
          2 
          3 class Client
          4 {
          5 public:
          6   Client();
          7   ~Client();
          8   Window parentID;
          9   Window windowID;
         10 };
         11 
         12 Client::Client(){}
         13 Client::~Client(){}
         14 
         15 int main()
         16 {
         17   perimos::database<Client>* pDB = new perimos::database<Client>;
         18   Client c;
         19 
         20   for (int a=1;a<10;++a) {
         21     c.windowID = a;
         22     pDB->add_entry(c.windowID,c);
         23   }
         24 
         25   Window wid = 3;
         26   pDB->remove_entry(wid);
         27 
         28   delete pDB;
         29   return 0;
         30 }
    perimosDatabase.hpp
    Code:
          1 #include <iostream>
          2 #include <map>
          3 
          4 /*extern "C" {
          5   #include <X11/Xlib.h> // Window definition
          6 }*/
          7 typedef unsigned long int Window;
          8 namespace perimos
          9 {
         10   template<class T> // T is the client type.
         11   class database
         12   {
         13   private:
         14     std::map<Window,T> db;
         15     typename std::map<Window,T>::iterator pEntry;
         16     bool locate(Window&);
         17   public:
         18     database();
         19     ~database();
         20     bool add_entry(Window&,T&);
         21     bool remove_entry(Window&);
         22     T& get_entry(Window&);
         23     void print();
         24   };
         25 } // namespace
    perimosDatabase.cpp
    Code:
          1 #include "perimosDatabase.hpp"
          2 
          3 template<class T>
          4 perimos::database<T>::database()
          5 {
          6 }
          7 template<class T>
          8 perimos::database<T>::~database()
          9 {
         10 }
         11 /*********************************************************
         12 ** Prototype:   locate(Window&)
         13 ** Parameters:  1
         14 *** Window&:    The window identity of the client.
         15 ** Returns:     True if the entry was found and false otherwise.
         16 ** Comments:    Private function.
         17 */
         18 template<class T>
         19 bool perimos::database<T>::locate(Window& wID)
         20 {
         21   pEntry = db.find(wID);
         22   if (pEntry != db.end())
         23     return true;
         24   return false;
         25 }
         26 /*********************************************************
         27 ** Prototype:   add_entry(Window&,T&)
         28 ** Parameters:  2
         29 *** Window&:    The window identity of the client.
         30 *** T&:         The client object.
         31 ** Returns:     True if the entry was added and false otherwise.
         32 ** Comments:    If false is returned, then the window identity was more than
         33                 likely a duplicate.
         34 */
         35 template<class T>
         36 bool perimos::database<T>::add_entry(Window& wID,T& c)
         37 {
         38   if (db.insert(std::make_pair(wID,c)).second)
         39     return true;
         40   std::cout<<""<<std::endl;
         41   return false;
         42 }
         43 /*********************************************************
         44 ** Prototype:   remove_entry(Window&)
         45 ** Parameters:  1
         46 *** Window&:    The window identity of the client
         47 ** Returns:     True if the entry was removed and false otherwise.
         48 ** Comments:    If false is returned, then the window identity didn't exist.
         49 */
         50 template<class T>
         51 bool perimos::database<T>::remove_entry(Window& wID)
         52 {
         53   if (locate(wID)) {
         54     db.erase(pEntry);
         55     return true;
         56   }
         57   return false;
         58 }
         59 /*********************************************************
         60 ** Prototype:   get_entry(Window&)
         61 ** Parameters:  1
         62 *** Window&:    The window identity of the client.
         63 ** Returns:     A reference to the client object stored in the database.
         64 ** Comments:    If the window identity does not exist, then the `windowID' of
         65                 returned object will equal zero (0). Ensure this is checked!
         66 */
         67 template<class T>
         68 T& perimos::database<T>::get_entry(Window& wID)
         69 { 
         70   locate(wID);
         71   return pEntry->second;
         72 }
         73 /*********************************************************
         74 ** Prototype:   print()
         75 ** Parameters:  0
         76 ** Returns:     void
         77 ** Comments:    For debugging purposes only.
         78 */
         79 template<class T>
         80 void perimos::database<T>::print()
         81 { 
         82   for (pEntry = db.begin();pEntry!=db.end();++pEntry)
         83     std::cout<<pEntry->second.windowID<<":"<<&pEntry->second<<std::endl;
         84 }
    The problem is: when I compile, below is the error I get:

    Command:
    Code:
    g++ perimosMain.cpp perimosDatabase.cpp -o perimos
    Error:
    Code:
    /var/tmp//ccFSVViv.o: In function `main':
    /var/tmp//ccFSVViv.o(.text+0x4c): undefined reference to `perimos::database<Client>::database()'
    /var/tmp//ccFSVViv.o(.text+0xbf): undefined reference to `perimos::database<Client>::add_entry(unsigned long&, Client&)'
    /var/tmp//ccFSVViv.o(.text+0xdf): undefined reference to `perimos::database<Client>::remove_entry(unsigned long&)'
    /var/tmp//ccFSVViv.o(.text+0xf9): undefined reference to `perimos::database<Client>::~database()'
    However, if in perimosMain.cpp I change #include "perimosDatabase.hpp" to #include "perimosDatabase.cpp" it compiles.

    Could some please shed some light on my problem here?

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Your perimosDatabase.cpp doesn't use the namespace used in the header file?
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User Russell's Avatar
    Join Date
    May 2004
    Posts
    71
    Sure it does:
    Code:
          3 template<class T>
          4 perimos::database<T>::database()
          5 {
          6 }
          7 template<class T>
          8 perimos::database<T>::~database()
          9 {
         10 }

  4. #4
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Templates must be completely implemented in the headers, otherwise the compiler can't access them.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  5. #5
    Registered User Russell's Avatar
    Join Date
    May 2004
    Posts
    71
    I not long ago worked out the problem was with the template, yet I'm still not quite sure what. Could you explain it some more please?

  6. #6
    Registered User Russell's Avatar
    Join Date
    May 2004
    Posts
    71
    Do you mean that what's in perimosDatabase.cpp should be merged into perimosDatabase.hpp?

  7. #7
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Templates aren't real code that is compiled. Instead, the compiler creates real code by substituting the template parameters with the actual types and constants.
    Now, this instantiation only happens when it is actually needed. So, if you have three files:
    a.cpp
    b.hpp
    b.cpp
    with b.hpp containing a template class b, b.cpp its implementation and a.cpp using it then the following happens when compiling:
    b.cpp is compiled. No instantiations are necessary, no code is generated, no code is compiled. b.o is practically empty.
    a.cpp is compiled. b<int> (for example) is required and instantiated from all the code the compiler knows at that moment - which is only b.hpp, because only that file is included from a.cpp. b.hpp only contains declarations. That's enough for the compiler, it creates and compiles code that uses b<int>. a.o contains code and references to members of b<int>.
    Final step, the linker. It gets a.o and b.o as input. It finds the references to b<int>::b, b<int>::do_stuff etc and looks for implementations. a.o doesn't contain them: the compiler didn't have access to the implementation code. b.o doesn't contain them either: there was no need to instantiate b<int> while compiling b.cpp. So the linker creates a load of unresolved reference errors.

    The solution is, as I said, to transfer all code from b.cpp to b.hpp (or a file included from there, e.g. bimpl.hpp). This way, the compiler has access to the implementation when instantiating b<int> and all is well.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  8. #8
    Registered User Russell's Avatar
    Join Date
    May 2004
    Posts
    71
    I understand. Thanks, CornedBee.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Getting an error with OpenGL: collect2: ld returned 1 exit status
    By Lorgon Jortle in forum C++ Programming
    Replies: 6
    Last Post: 05-08-2009, 08:18 PM
  2. Undefined Reference Compiling Error
    By AlakaAlaki in forum C++ Programming
    Replies: 1
    Last Post: 06-27-2008, 11:45 AM
  3. Screwy Linker Error - VC2005
    By Tonto in forum C++ Programming
    Replies: 5
    Last Post: 06-19-2007, 02:39 PM
  4. C OpenGL Compiler Error?
    By Matt3000 in forum C Programming
    Replies: 12
    Last Post: 07-07-2006, 04:42 PM
  5. c++ linking problem for x11
    By kron in forum Linux Programming
    Replies: 1
    Last Post: 11-19-2004, 10:18 AM