使用 g++ 编译类模板 - 未定义的符号

问题描述 投票:0回答:2

我正在尝试在命名空间 cop4530 中编译一个新的类模板。你知道我为什么要拿回这个吗?这些函数确实存在,并且编译器并没有通过详细说明来帮助我。我已经完成了这个线程所说的事情,但我仍然得到未定义的符号

g++ -o proj2.x  test_list.o
Undefined symbols for architecture x86_64:
  "cop4530::List<int>::iterator::operator++(int)", referenced from:
      _main in test_list.o
  "cop4530::List<int>::iterator::operator*()", referenced from:
      _main in test_list.o
  "cop4530::List<int>::iterator::operator++()", referenced from:
      _main in test_list.o
      cop4530::List<int>::List(int, int const&)in test_list.o
  "cop4530::List<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::iterator::operator++(int)", referenced from:
      _main in test_list.o
  "cop4530::List<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::iterator::operator*()", referenced from:
      _main in test_list.o
  "cop4530::List<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::iterator::operator++()", referenced from:
      _main in test_list.o
      cop4530::List<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::List(int, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)in test_list.o
  "cop4530::List<int>::iterator::iterator(cop4530::List<int>::Node*)", referenced from:
      cop4530::List<int>::erase(cop4530::List<int>::iterator)in test_list.o
      cop4530::List<int>::clear()  in test_list.o
      cop4530::List<int>::insert(cop4530::List<int>::iterator, int const&)in test_list.o
  "cop4530::List<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::iterator::iterator(cop4530::List<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::Node*)", referenced from:
      cop4530::List<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::erase(cop4530::List<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::iterator)in test_list.o
      cop4530::List<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::clear()in test_list.o
      cop4530::List<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::insert(cop4530::List<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::iterator, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)in test_list.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
make: *** [List_executable] Error 1

我的标题是由教科书编写的,没有任何更改(或可以针对该项目进行更改),因此问题不存在。与驱动程序“test_list”相同。在头文件的末尾有一个包含(上面所说的问题[它不称为线程,我被告知]要做什么。)

无论如何标题:

#ifndef DL_LIST_H
#define DL_LIST_H
#include <iostream>

namespace cop4530 {

template <typename T>
class List {
 private:
    // nested Node class
    struct Node {
    T data;
    Node *prev;
    Node *next;

    Node(const T & d = T(), Node *p = NULL, Node *n = NULL) 
        : data(d), prev(p), next(n) {}
    };

 public:
    //nested const_iterator class
    class const_iterator {
    public:
    const_iterator(); // default zero parameter constructor
    const T & operator*() const; // operator*() to return element

    // increment/decrement operators
    const_iterator & operator++();
    const_iterator operator++(int);
    const_iterator & operator--();
    const_iterator operator--(int);

    // comparison operators
    bool operator==(const const_iterator &rhs) const;
    bool operator!=(const const_iterator &rhs) const;

    protected:
    Node *current; // pointer to node in List
    T & retrieve() const; // retrieve the element refers to
    const_iterator(Node *p); // protected constructor

    friend class List<T>;
    };

    // nested iterator class
    class iterator : public const_iterator {
    public:
    iterator() {}
    T & operator*();
    const T & operator*() const;

    // increment/decrement operators
    iterator & operator++();
    iterator operator++(int);
    iterator & operator--();
    iterator operator--(int);

    protected:
    iterator(Node *p);
    friend class List<T>;
    };

 public:
    // constructor, desctructor, copy constructor
    List(); // default zero parameter constructor
    List(const List &rhs); // copy constructor
    // num elements with value of val
    explicit List(int num, const T& val = T()); 
    // constructs with elements [start, end)
    List(const_iterator start, const_iterator end); 

    ~List(); // destructor

    // assignment operator
    const List& operator=(const List &rhs);

    // member functions
    int size() const; // number of elements
    bool empty() const; // check if list is empty
    void clear(); // delete all elements
    void reverse(); // reverse the order of the elements

    T &front(); // reference to the first element
    const T& front() const;
    T &back(); // reference to the last element
    const T & back() const; 

    void push_front(const T & val); // insert to the beginning
    void push_back(const T & val); // insert to the end
    void pop_front(); // delete first element
    void pop_back(); // delete last element

    void remove(const T &val); // remove all elements with value = val

    // print out all elements. ofc is deliminitor
    void print(std::ostream& os, char ofc = ' ') const; 

    iterator begin(); // iterator to first element
    const_iterator begin() const;
    iterator end(); // end marker iterator
    const_iterator end() const; 
    iterator insert(iterator itr, const T& val); // insert val ahead of itr
    iterator erase(iterator itr); // erase one element
    iterator erase(iterator start, iterator end); // erase [start, end)


private:
    int theSize; // number of elements
    Node *head; // head node
    Node *tail; // tail node

    void init(); // initialization
};

// overloading comparison operators
template <typename T>
bool operator==(const List<T> & lhs, const List<T> &rhs);

template <typename T>
bool operator!=(const List<T> & lhs, const List<T> &rhs);

// overloading output operator
template <typename T>
std::ostream & operator<<(std::ostream &os, const List<T> &l);

// include the implementation file here
#include "List.cpp"

} // end of namespace 4530

#endif

这是 .cpp 文件。还没有完全完成:

using namespace std;

// --------------------- CONST_ITERATOR --------------------- //
template <class T>
List<T>::const_iterator::const_iterator()
{ // default zero-parameter constructor. Set pointer current to NULL.
  current = NULL;
}

template <class T>
const T& List<T>::const_iterator::operator*() const
{ // returns a reference to the corresponding element in the list by calling retrieve() member function.
  return retrieve();
}

template <class T>
typename List<T>::const_iterator& List<T>::const_iterator::operator++()
{
  current = current->next;
  return *this;
}
template <class T>
typename List<T>::const_iterator List<T>::const_iterator::operator++(int)
{
  const_iterator old = *this;
  ++( *this );
  return old;
}
template <class T>
typename List<T>::const_iterator& List<T>::const_iterator::operator--()
{
  current = current->prev;
  return *this;
}
template <class T>
typename List<T>::const_iterator List<T>::const_iterator::operator--(int)
{
  const_iterator old = *this;
  --( *this );
  return old;
}

template <class T>
bool List<T>::const_iterator::operator==(const const_iterator &rhs) const
  {return current == rhs.current;}

template <class T>
bool List<T>::const_iterator::operator!=(const const_iterator &rhs) const
  {return !( *this == rhs );}

template <class T>
T& List<T>::const_iterator::retrieve() const
{ // return a reference to the corresponding element in the list.
  return current->data;
}

template <class T>
List<T>::const_iterator::const_iterator(Node *p)
{ // one-parameter constructor
  // Set pointer current to the given node pointer p.
  current = p;
}

// --------------------- ITERATOR --------------------- //

template <class T>
T& List<T>::iterator::operator*()
{
  return retreive();
}

template <class T>
const T& List<T>::iterator::operator*() const
{
  return retreive();
}

template <class T>
List<T>::iterator & List<T>::iterator::operator++()
{
  current = current->next;
  return *this;
}

template <class T>
List<T>::iterator List<T>::iterator::operator++(int)
{
  const_iterator old = *this;
  ++( *this );
  return old;
}

template <class T>
List<T>::iterator & List<T>::iterator::operator--()
{
  current = current->prev;
  return *this;
}

template <class T>
List<T>::iterator List<T>::iterator::operator--(int)
{
  const_iterator old = *this;
  --( *this );
  return old;
}

template <class T>
List<T>::iterator::iterator(Node *p)
{ // one-parameter constructor
  // Set current to the given node pointer p
  current = p;
}

// --------------------- LIST --------------------- //

template <class T>
List<T>::List()
{ init(); }

template <class T>
List<T>::List( const List & rhs )
{ // Copy constructor
  init();
  *this = rhs;
}

template <class T>
List<T>::List(int num, const T& val)
{ //Constructs a list with num elements, all initialized with value val
  init();
  iterator itr = begin();
  for (int i = 0; i < num; ++i)
  {
    insert(itr, val);
    ++itr;
  }
}

template <class T>
List<T>::List(const_iterator start, const_iterator end)
{ // Constructs a List w/ elements from another List between
  // start and end. [includes start, not end) 
  ///////////
}

template <class T>
List<T>::~List()
{ // Destructor
  clear();
  delete head;
  delete tail;
}

template <class T>
const typename List<T>::List& List<T>::operator=(const List &rhs)
{ // Assignment operator
  List<T>::iterator ritr = rhs.first();
  List<T>::iterator itr = begin();

  if( this != &rhs )
    {
      clear();
      for( ; !ritr.isPastEnd( ); ritr.advance( ), itr.advance( ) )
    insert( ritr.retrieve( ), itr );
    }
  return *this;
}

template <class T>
int List<T>::size() const
{ // return the number of elements in the List
  return theSize;
}

template <class T>
bool List<T>::empty() const
{ // check if list is empty
  return head->next == NULL;
}

template <class T>
void List<T>::clear()
{ // delete all elements
  while( !isEmpty( ) )
    erase( begin().retreive() );
}

template <class T>
void List<T>::reverse()
{ // reverse the order of the elements
  /////////////
}

template <class T>
T& List<T>::front()
{ // reference to the first element
  return head->next->data;
}

template <class T>
T& List<T>::back()
{ // reference to the last element
  return tail->prev->data;
}

template <class T>
void List<T>::push_front(const T & val)
{ // insert to the beginning

}

template <class T>
void List<T>::push_back(const T & val)
{ // insert to the end

}

template <class T>
void List<T>::pop_front()
{ // delete first element

}

template <class T>
void List<T>::pop_back()
{ // delete last element

}

template <class T>
void List<T>::remove(const T &val)
{ // remove all elements with value = val

}

template <class T>
void List<T>::print(std::ostream& os, char ofc) const
{ // print out all elements. ofc is deliminitor

}

template <class T>
typename List<T>::iterator List<T>::begin()
{ // iterator to first element
  return List<T>::iterator( head->next );
}

template <class T>
typename List<T>::iterator List<T>::end()
{ // end marker iterator
  return List<T>::iterator( tail->prev );
}

template <class T>
typename List<T>::iterator List<T>::insert( iterator itr, const T & x )
{
  Node *p = itr.current;
  theSize++;
  return iterator( p->prev = p->prev->next = new Node( x, p->prev, p) );
}

template <class T>
typename List<T>::iterator List<T>::erase( iterator itr )
{
  Node *p = itr.current;
  iterator retVal( p->next );
  p->prev->next = p->next;
  p->next->prev = p->prev;
  delete p;
  theSize--;

  return retVal;
}

template <class T>
typename List<T>::iterator List<T>::erase( iterator start, iterator end )
{
  for( iterator itr = start; itr != end; )
    itr = erase( itr );

  return end;
}

template <class T>
void List<T>::init()
{ // Initaialize the member variables of a List
  theSize = 0;
  head = new Node;
  tail = new Node;
  head->next = tail;
  tail->prev = head;
}


// --------- OVERLOADS --------- //

template <typename T>
bool operator==(const List<T> & lhs, const List<T> &rhs)
{

}

template <typename T>
bool operator!=(const List<T> & lhs, const List<T> &rhs)
{

}

template <typename T>
std::ostream & operator<<(std::ostream &os, const List<T> &l)
{

}

让我补充一点,我感谢所提供的所有帮助。我是一名学生,我正在努力学习。

c++ gcc g++
2个回答
2
投票

模板类方法在第一次使用时被实例化,因此

List<int>
List<string>
的定义必须从调用单元可见。

您的教科书似乎假设编译器支持外部模板定义,而 GCC 不支持。

一个简单的修复方法是将 List.cpp 文件内容复制粘贴到您要修复的编译单元中。


1
投票

现在您已经发布了代码,答案很简单(实际上与您链接的问题的答案相同):

编译必须在实例化模板函数(和模板类的方法)时查看它们的定义。因此,模板函数/方法不应在 .cpp

 文件中定义。将它们放在标题中(并在您使用模板时包含该标题)。

© www.soinside.com 2019 - 2024. All rights reserved.