C++ Visual Studio 10 上编译错误
使用 Visual Studio 编译这个简单的程序时出现以下错误:
error LNK2019: unresolved external symbol "public: void __thiscall CoList<int>::enqueue(int)" (?enqueue@?$CoList@H@@QAEXH@Z) referenced in function _main
error LNK2019: unresolved external symbol "public: virtual __thiscall CoList<int>::~CoList<int>(void)" (??1?$CoList@H@@UAE@XZ) referenced in function _main
error LNK2019: unresolved external symbol "public: int __thiscall CoList<int>::dequeue(void)" (?dequeue@?$CoList@H@@QAEHXZ) referenced in function _main
error LNK2019: unresolved external symbol "public: int __thiscall CoList<int>::count(void)" (?count@?$CoList@H@@QAEHXZ) referenced in function _main
error LNK2019: unresolved external symbol "public: __thiscall CoList<int>::CoList<int>(void)" (??0?$CoList@H@@QAE@XZ) referenced in function _main
error LNK1120: 5 unresolved externals
我的程序非常简单。我不使用外部库,只使用“iostream”和“异常”标头...这是完整的代码:
CoList.h
#pragma once
#include "CoListItem.h"
template <class T>
class CoList
{
public:
CoList();
virtual ~CoList();
void enqueue(T value);
T dequeue();
T *peek();
int count();
private:
CoListItem<T> *m_root;
int m_count;
};
CoListItem.h
#pragma once
template <class T>
class CoListItem
{
public:
CoListItem();
virtual ~CoListItem();
T value;
CoListItem *next;
};
CoList.cpp
#include "CoList.h"
#include <exception>
template <class T>
CoList<T>::CoList()
{
}
template <class T>
CoList<T>::~CoList()
{
}
template <class T>
void CoList<T>::enqueue(T value)
{
if (this->m_root != NULL) {
this->m_root = new CoListItem<T>();
this->m_root->value = value;
this->m_root->next = NULL;
} else {
CoListItem<T> *tempitem = new CoListItem<T>();
tempitem->value = value;
tempitem->next = this->m_root;
this->m_root = tempitem;
}
this->m_count++;
}
template <class T>
T CoList<T>::dequeue()
{
if (this->m_root == NULL) {
throw std::exception();
} else {
T retval = this->m_root->value;
CoListItem *next = this->m_root->next;
delete this->m_root;
this->m_root = next;
return retval;
}
}
template <class T>
T *CoList<T>::peek()
{
if (this->m_root == NULL) {
return NULL;
} else {
return *this->dequeue();
}
}
template <class T>
int CoList<T>::count()
{
return this->m_count;
}
CoListItem.cpp
#include "CoListItem.h"
template <class T>
CoListItem<T>::CoListItem()
{
}
template <class T>
CoListItem<T>::~CoListItem()
{
}
最后是主要功能:
#include <iostream>
#include "CoList.h"
#include "CoListItem.h"
using namespace std;
int main(int argc, char *argv[])
{
CoList<int> list;
for(int i = 0; i < 10; i++)
list.enqueue(i);
cout << "Count: " << list.count() << endl;
for(int i = 0; i < 10; i++)
cout << "Item: " << list.dequeue() << endl;
cout << "Count: " << list.count() << endl;
int wait = 0;
cin >> wait;
}
如您所见是一个非常简单的使用链表的队列实现......
I'm getting the following error while compiling this simple program using Visual Studio:
error LNK2019: unresolved external symbol "public: void __thiscall CoList<int>::enqueue(int)" (?enqueue@?$CoList@H@@QAEXH@Z) referenced in function _main
error LNK2019: unresolved external symbol "public: virtual __thiscall CoList<int>::~CoList<int>(void)" (??1?$CoList@H@@UAE@XZ) referenced in function _main
error LNK2019: unresolved external symbol "public: int __thiscall CoList<int>::dequeue(void)" (?dequeue@?$CoList@H@@QAEHXZ) referenced in function _main
error LNK2019: unresolved external symbol "public: int __thiscall CoList<int>::count(void)" (?count@?$CoList@H@@QAEHXZ) referenced in function _main
error LNK2019: unresolved external symbol "public: __thiscall CoList<int>::CoList<int>(void)" (??0?$CoList@H@@QAE@XZ) referenced in function _main
error LNK1120: 5 unresolved externals
My program is very simple. I don't use external libraries, just the 'iostream' and 'exception' headers... Here is the full code:
CoList.h
#pragma once
#include "CoListItem.h"
template <class T>
class CoList
{
public:
CoList();
virtual ~CoList();
void enqueue(T value);
T dequeue();
T *peek();
int count();
private:
CoListItem<T> *m_root;
int m_count;
};
CoListItem.h
#pragma once
template <class T>
class CoListItem
{
public:
CoListItem();
virtual ~CoListItem();
T value;
CoListItem *next;
};
CoList.cpp
#include "CoList.h"
#include <exception>
template <class T>
CoList<T>::CoList()
{
}
template <class T>
CoList<T>::~CoList()
{
}
template <class T>
void CoList<T>::enqueue(T value)
{
if (this->m_root != NULL) {
this->m_root = new CoListItem<T>();
this->m_root->value = value;
this->m_root->next = NULL;
} else {
CoListItem<T> *tempitem = new CoListItem<T>();
tempitem->value = value;
tempitem->next = this->m_root;
this->m_root = tempitem;
}
this->m_count++;
}
template <class T>
T CoList<T>::dequeue()
{
if (this->m_root == NULL) {
throw std::exception();
} else {
T retval = this->m_root->value;
CoListItem *next = this->m_root->next;
delete this->m_root;
this->m_root = next;
return retval;
}
}
template <class T>
T *CoList<T>::peek()
{
if (this->m_root == NULL) {
return NULL;
} else {
return *this->dequeue();
}
}
template <class T>
int CoList<T>::count()
{
return this->m_count;
}
CoListItem.cpp
#include "CoListItem.h"
template <class T>
CoListItem<T>::CoListItem()
{
}
template <class T>
CoListItem<T>::~CoListItem()
{
}
and finally the main function:
#include <iostream>
#include "CoList.h"
#include "CoListItem.h"
using namespace std;
int main(int argc, char *argv[])
{
CoList<int> list;
for(int i = 0; i < 10; i++)
list.enqueue(i);
cout << "Count: " << list.count() << endl;
for(int i = 0; i < 10; i++)
cout << "Item: " << list.dequeue() << endl;
cout << "Count: " << list.count() << endl;
int wait = 0;
cin >> wait;
}
As you can see it is a very simple Queue implementation using a linked list...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
函数模板(包括类模板的成员函数)的定义必须位于 .h 文件中,以便它们出现在使用它们的每个 cpp 文件中。这就是模板的工作原理。您不能将定义放入 cpp 文件中。从技术上讲,有一个
export
关键字可以实现此目的,但由于几乎没有实现支持它,因此它在新标准中被删除。阅读本文:包容模型
The definitions of function templates(including member functions of class templates) must be in the .h file so that they are present in every cpp file in which they are used. That's how templates work. You cant put the definitions into a cpp file. Technically, there is an
export
keyword which enables this but since almost no implementation supported it it was removed in the new standard.Read this: The inclusion model
template
定义对于使用它的代码应该是可见的。为此,#include
该“.cpp”文件例如,在您的情况下,您可以
#include“CoList.cpp”
而不是“CoList.h”
。等等。template
definitions should be visible to the code which is using it. For that,#include
that ".cpp" fileFor example, in your case you can
#include "CoList.cpp"
instead of"CoList.h"
. And so on.考虑一个采用 T 并执行模数 (%) 或简单加法 (+) 的模板函数。
您在这段代码中看不到错误。好吧。当我传递两个 int 时,它会被编译:
但是当我传递 float/double 时,它不会编译:
编译器将发出:
错误 C2296:'%':非法,左操作数的类型为 'double'
和其他相关错误。要点是,除非您为特定数据类型至少实例化一次模板代码,否则模板代码不会被编译。模板代码仍然是垃圾 - 编译器不关心代码中的实际内容。在您的情况下,CPP 只是编译器忽略的文本文件 - 所有这些。
话虽如此,当我使用运算符
+
而不是运算符%
时,它将适用于所有基本数据类型,但不适用于缺少operator + 的类
。在这种情况下,编译器将再次编译该数据类型(类)的模板内容。在某些情况下,编译器和链接器会协同工作以减少最终的二进制代码大小,当它们发现某些代码是重复的并且对于所有/多个数据类型都是相同的时。但那是另一种情况。
Consider a template function that takes T and performs modulus (%), or a simple addition (+) for that matter.
You see NO ERROR in this code. Alright. When I pass two ints it gets compiled:
But when I pass float/double it WONT compile:
Compiler will emit:
error C2296: '%' : illegal, left operand has type 'double'
and other related errors.The point is that template code doesn't get compiled until you instantiate it at least once for a particular data type. The template code stays junk - compiler doesn't care what actually inside the code. In your case the CPP is nothing but a text-file the compiler has ignored - All of it.
Having said that, when I use operator
+
, instead of operator%
it would work for all basic data-types, but not for classes that are missingoperator +
. In that case compiler will compile again the template-stuff for that data-type (the class).There are cases where compiler and linker work together to reduce final binary code size, when they see some code is duplicate and would be same for all/several data-types. But that's a different case.
这直接来自 Nicolai Josutis 的传奇书籍,
C++ 模板:完整指南
模板被编译两次:
这导致了模板处理实践中的一个重要问题。当函数模板以触发实例化的方式使用时,编译器将(在某些时候)需要查看该模板定义。当函数声明足以编译其使用时,这打破了函数通常的编译和链接区别。
因此,对于模板来说,声明和定义应该保存在同一个头文件中,以便它们在使用它们的每个 cpp 中都可见。
This is straight from Nicolai Josutis's legendary book,
C++ Templates: A complete Guide
Templates are compiled twice:
This leads to an important problem in the handling of templates practice. When a function template is used in a way that it triggers instantiation, a compiler will (at some point) need to see that template definition. This breaks the usual compile and link distinction for functions, when declaration of function is sufficient to compile the its use.
Thus, For a template the declaration and definition should be kept in the same header file so that they are visible in every cpp which uses them.