C++ Visual Studio 10 上编译错误

发布于 2024-11-25 03:23:46 字数 3526 浏览 2 评论 0原文

使用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

压抑⊿情绪 2024-12-02 03:23:46

函数模板(包括类模板的成员函数)的定义必须位于 .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

白日梦 2024-12-02 03:23:46

template 定义对于使用它的代码应该是可见的。为此,

  1. 将所有定义放入“.h”文件中
  2. 将定义放入“.cpp”文件中(用于代码分离)并
    #include 该“.cpp”文件

例如,在您的情况下,您可以 #include“CoList.cpp” 而不是 “CoList.h”。等等。

template definitions should be visible to the code which is using it. For that,

  1. Put all the definitions in ".h" file
  2. Put the definitions in ".cpp" file (for the code separation) and
    #include that ".cpp" file

For example, in your case you can #include "CoList.cpp" instead of "CoList.h". And so on.

千仐 2024-12-02 03:23:46

考虑一个采用 T 并执行模数 (%) 或简单加法 (+) 的模板函数。

template <class T>
T GetT(T t1, T t2)
{
    return t1%t2;
}

您在这段代码中看不到错误。好吧。当我传递两个 int 时,它会被编译:

GetT(10,20);

但是当我传递 float/double 时,它​​不会编译:

GetT(10.6, 20.5);

编译器将发出:错误 C2296:'%':非法,左操作数的类型为 'double' 和其他相关错误。
要点是,除非您为特定数据类型至少实例化一次模板代码,否则模板代码不会被编译。模板代码仍然是垃圾 - 编译器不关心代码中的实际内容。在您的情况下,CPP 只是编译器忽略的文本文件 - 所有这些。

话虽如此,当我使用运算符 + 而不是运算符 % 时,它将适用于所有基本数据类型,但不适用于缺少 operator + 的类。在这种情况下,编译器将再次编译该数据类型(类)的模板内容。

在某些情况下,编译器和链接器会协同工作以减少最终的二进制代码大小,当它们发现某些代码是重复的并且对于所有/多个数据类型都是相同的时。但那是另一种情况。

Consider a template function that takes T and performs modulus (%), or a simple addition (+) for that matter.

template <class T>
T GetT(T t1, T t2)
{
    return t1%t2;
}

You see NO ERROR in this code. Alright. When I pass two ints it gets compiled:

GetT(10,20);

But when I pass float/double it WONT compile:

GetT(10.6, 20.5);

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 missing operator +. 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.

迷爱 2024-12-02 03:23:46

这直接来自 Nicolai Josutis 的传奇书籍,

C++ 模板:完整指南

模板被编译两次:

  • 没有实例化,模板本身就会被检查语法正确,这里发现分号等语法错误。
  • 在实例化时,将检查模板代码以确保所有调用都有效。发现无效调用,例如不支持的函数调用。

这导致了模板处理实践中的一个重要问题。当函数模板以触发实例化的方式使用时,编译器将(在某些时候)需要查看该模板定义。当函数声明足以编译其使用时,这打破了函数通常的编译和链接区别。


因此,对于模板来说,声明和定义应该保存在同一个头文件中,以便它们在使用它们的每个 cpp 中都可见。

This is straight from Nicolai Josutis's legendary book,

C++ Templates: A complete Guide

Templates are compiled twice:

  • Without instantiation, the template itself is checked for correct syntax, Syntax errors such as semicolon are discovered here.
  • As the time of instantiation, the templates code is checked to ensure that all calls are valid. Invalid calls are discovered such as unsupported function calls.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文