我正在尝试在Micheal T. Goodrich等人的“c ++中的数据结构和算法”中测试SinglyLinked List示例。我添加了一些作者省略的细节,以使其可以运行。
以下是代码:
#ifndef S_LINKED_LIST
#define S_LINKED_LIST
template <typename E>
class SLinkedList;
template <typename E>
class SNode
{
private:
E elem;
SNode<E> * next;
friend class SLinkedList<E>;
};
template <typename E>
class SLinkedList
{
private:
SNode<E> * head;
public:
SLinkedList();
~SLinkedList();
bool empty() const;
const E& front() const;
void addFront(const E& e);
void removeFront();
};
#endif /*SLinkedList.h*/
实现:
#include "SLinkedList.h"
#include <iostream>
template <typename E>
SLinkedList<E>::SLinkedList():head(NULL){}
template <typename E>
SLinkedList<E>::~SLinkedList()
{while(!empty()) removeFront();}
template <typename E>
bool SLinkedList<E>::empty() const
{return head == NULL;}
template <typename E>
const E& SLinkedList<E>::front() const
{return head->elem;}
template <typename E>
void SLinkedList<E>::addFront(const E& e)
{
SNode<E> * newNode = new SNode<E>;
newNode->elem = e;
newNode->next = head;
head = newNode;
}
template <typename E>
void SLinkedList<E>::removeFront()
{
SNode<E> * old = head;
head = old->next;
delete old;
}/*SLinkedList.cpp*/
测试文件:
#include <iostream>
#include "SLinkedList.h"
int main()
{
SLinkedList<std::string> newlist;
newlist.addFront("MSP");
std::cout << newlist.front();
return 0;
}/*test_slinkedlist.cpp*/
运行g++ -c SLinkedList.cpp
和g++ -c test_slinkedlist.cpp
后
我没有错误地获得了目标文件SLinkedList.o
和test_slinkedlist.o
。
但是当我运行g ++ -o result test_slinkedlist.o SLinkedList.o时,我收到了链接器错误:
Undefined symbols for architecture x86_64:
...
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
我花了一天时间调试此链接器问题但找不到。我怀疑这很明显。
操作系统:OS X
Undefined symbols for architecture x86_64:
"SLinkedList<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::addFront(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)", referenced from:
_main in test_slinkedlist.o
"SLinkedList<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::SLinkedList()", referenced from:
_main in test_slinkedlist.o
"SLinkedList<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::~SLinkedList()", referenced from:
_main in test_slinkedlist.o
"SLinkedList<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >::front() const", referenced from:
_main in test_slinkedlist.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
答案 0 :(得分:0)
实现:
你没有说出来,但我们可以假设实施在SLinkedList.cpp
。
Undefined symbols for architecture x86_64:
...
在...
中,您忽略了错误消息中最重要的部分。但是,我们可以猜测SLinkedList<std::string>::addFront(...)
是未解析的符号之一。
您的问题是模板方法(即实现)的 body 必须出现在每个编译单元中使用过,并且您违反了该规则,将此正文放入单独的.cpp
文件中,编译器编译test_slinkedlist.cpp
时 。
这就是为什么模板正文最常包含在SLinkedList.h
中(请注意.h
,而不是.cpp
)。另请参阅this answer。
P.S。从技术上讲,&#34;必须&#34;上面的内容不正确:您还可以使用显式实例化使编译器生成您需要的模板方法体。但这比将实现放入.h
文件更为先进。
答案 1 :(得分:0)
在C ++中,您无法将未实例化的模板编译和链接为单独的编译单元。
SLinkedList.cpp没有实例化模板,因此它基本上不会编译。
这就是仅模板库始终只有标头的原因。
你有几个选择。
在其中实例化您的SLinkedList SLinkedList.cpp的编译单元,让编译器为模板实例生成实际代码,或将头和cpp合并到一个文件中。