0

I've seen this question asked a lot on this website, but trying the solutions offered on here have yet to work with my program. So, I apologize for asking this question for the umpteenth time, but nothing is working for me.

I compile the following

g++ deque.cpp deque.h driver.cpp

and then get the error

/tmp/ccvkttRj.o: In function `main':
driver.cpp:(.text+0x20): undefined reference to `Deque<int>::Deque()'
driver.cpp:(.text+0x42): undefined reference to `Deque<int>::addBack(int const&)'
driver.cpp:(.text+0x6f): undefined reference to `Deque<int>::addFront(int const&)'
driver.cpp:(.text+0x8d): undefined reference to `Deque<int>::Deque(Deque<int> const&)'
driver.cpp:(.text+0xa7): undefined reference to `Deque<int>::addBack(int const&)'
driver.cpp:(.text+0xcf): undefined reference to `Deque<int>::isEmpty() const'
driver.cpp:(.text+0xe2): undefined reference to `Deque<int>::removeFront()'
driver.cpp:(.text+0x125): undefined reference to `Deque<int>::isEmpty() const'
driver.cpp:(.text+0x138): undefined reference to `Deque<int>::removeBack()'
driver.cpp:(.text+0x15f): undefined reference to `Deque<int>::~Deque()'
driver.cpp:(.text+0x16b): undefined reference to `Deque<int>::~Deque()'
driver.cpp:(.text+0x190): undefined reference to `Deque<int>::~Deque()'
driver.cpp:(.text+0x1a1): undefined reference to `Deque<int>::~Deque()'
collect2: error: ld returned 1 exit status

As far as I can tell, I'm using #include and #ifndef in the appropriate places, my method signatures are the same in my all my files. But I have to be wrong otherwise I wouldn't be getting this error.

Here is my program for a deque:

  1. the header

    #ifndef DEQUE_H
    #define DEQUE_H
    #include <iostream>
    using namespace std;
    
    template <class Object>
    class Deque
    {
     public:
      Deque(); // Constructor.
      Deque(const Deque &rhs); // Copy constructor.
      ~Deque(); // Destructor.
    
      bool isEmpty() const; // Is deque empty.
      int size() const; // Returns # of deque nodes.
      const Object &getFront() const; // Retrieve front node.
      const Object &getBack() const; // Retrieve tail node.
    
      void clear(); // Clears all nodes from deque.
      void addFront(const Object &obj); // Add a new node to the front.
      void addBack(const Object &obj); // Add a new node to the rear.
      Object removeFront(); // Remove front node.
      Object removeBack(); // Remove rear node.
    
      const Deque &operator=(const Deque &rhs); // Assignment.
    
     private:
      struct DequeNode
      {
        Object item;
        DequeNode *next;
        DequeNode *prev;
      };
      DequeNode *front;
      DequeNode *back;
    };
    
    #endif
    
  2. the cpp

    #include "deque.h"
    
    template <class Object>
    Deque<Object>::Deque() // Constructor.
    {
      front = back = NULL;
    }
    
    template <class Object>
    Deque<Object>::Deque(const Deque &rhs) // Copy constructor.
    {
      front = back = NULL;
      *this = rhs;
    }
    
    template <class Object>
    Deque<Object>::~Deque()  // Destructor.
    {
      clear();
    }
    
    template <class Object>
    bool Deque<Object>::isEmpty() const // Check if deque is empty.
    {
      return front == NULL;
    }
    
    template <class Object>
    int Deque<Object>::size() const // Returns # of nodes.
    {
      int i = 0;
      for (DequeNode *ptr = front; ptr != NULL; ptr = ptr->next)
        ++i;
    
      return i;
    }
    
    template <class Object>
    const Object &Deque<Object>::getFront() const // Retrieve front node.
    {
      if (isEmpty())
        throw "empty queue";
    
      return front->item;
    }
    
    template <class Object>
    const Object &Deque<Object>::getBack() const // Retrieve rear node.
    {
      if (isEmpty())
        throw "empty queue";
    
      return back->item;
    }
    
    template <class Object>
    void Deque<Object>::addFront(const Object &obj) // Add a new node to the front.
    {
      DequeNode *newPtr = new DequeNode; // Allocate the node in memory.
      newPtr->item = obj; // Insert obj.
      newPtr->next = front; // What once was front will become next.
      newPtr->prev = NULL; // Front node's prev is always NULL.
    
      if (isEmpty()) // If empty back points to the same as front.
        back = newPtr;
      else
        front->prev = newPtr; // The old front now points the new insert.
    
      front = newPtr; // Front now points to the new insert.
    }
    
    template <class Object>
    void Deque<Object>::addBack(const Object &obj) // Add a new node to the back.
    {
      DequeNode *newPtr = new DequeNode; // Allocate the node in memory.
      newPtr->item = obj; // Insert obj.
      newPtr->next = NULL; // The last node always points to null.
      newPtr->prev = back; // Inserting back, so point to what once was the last node.
    
      if (isEmpty()) // If empty front points to the same as back.
        front = newPtr;
      else
        back->next = newPtr; // Old back needs to point to new insert, not NULL.
    
      back = newPtr; // Back now points to the new insert.
    }
    
    template <class Object>
    Object Deque<Object>::removeFront() // Remove front node.
    {
      Object frontItem = getFront(); // Save what will be removed, so it can be returned.
      DequeNode *toDelete = front; // What will be deleted.
    
      if (front == back) // Only 1 item in the deque.
        front = back = NULL;
      else
        {
          front = front->next; // Move the next node up.
          front->prev = NULL; // Front node always points to NULL.
        }
      delete toDelete; // Goodbye what once was front;
    
      return frontItem;
    }
    
    template <class Object>
    Object Deque<Object>::removeBack() // Remove back/last node.
    {
      Object backItem = getBack(); // Save what will be removed, so it can be returned.
      DequeNode *toDelete = back; // What will be deleted.
    
      if (front == back) // Only 1 item in the deque.
        front = back = NULL;
      else
        {
          back = back->prev; // Move back up the list.
          back->next = NULL; // Last node always points to NULL.
        }
      delete toDelete; // Goodbye what once was back.
    
      return backItem;
    }
    
    template <class Object>
    const Deque<Object> &Deque<Object>::operator=(const Deque &rhs) // Assignment op.
    {
      if (this != &rhs) // Avoid self assignment.
        {
          clear(); // Not sure why clear, I'll have to come back to this.
          for (DequeNode *ptr = rhs.front; ptr != NULL; ptr = ptr->next)
        addBack(ptr->item);
        }
    
      return *this;
    }
    
  3. main

    #include <iostream>
    #include "deque.h"
    
    using namespace std;
    
    int main( ) {
     Deque<int> deque1;
     int item;
    
     for ( int j = 0; j < 5; j++ )
       deque1.addBack( j );
     for ( int j = 5; j < 10; j++ )
       deque1.addFront( j );
    
     Deque<int> deque2 = deque1;
     deque2.addBack( 10 );
    
     cout << "deque1: " << endl;
     while ( !deque1.isEmpty( ) )
       cout << deque1.removeFront( ) << endl;
    
     cout << "deque2: " << endl;
     while ( !deque2.isEmpty( ) )
       cout << deque2.removeBack( ) << endl;
    }
    
boy
  • 39
  • 2
  • I knew a compiler that could do that, but it required a cxx_repository directory and frankly, it was not a good idea :) – Jean-François Fabre Sep 22 '16 at 21:33
  • I'm not sure I quite understand. According to the FAQ in that linked question, I'm supposed to add a specifier after every method in my cpp file? For example in my cpp if I put under my constructor "template Deque::Deque();" then for addBack I put "template void Deque::addBack(const int &obj);" and it makes the errors go away. But this seems horribly inefficient, and seems to defeat the purpose of the ambiguity of the template. Am I just misunderstanding how template is used? – boy Sep 22 '16 at 23:13

0 Answers0