简体   繁体   English

C++ 在 Visual Studio 10 上编译错误

[英]C++ compile error on Visual Studio 10

I'm getting the following error while compiling this simple program using Visual Studio:使用 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:我不使用外部库,只使用 'iostream' 和 'exception' 标头...这是完整代码:

CoList.h 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 CoListItem.h

#pragma once

template <class T>
class CoListItem
{

public:

    CoListItem();
    virtual ~CoListItem();

    T value;
    CoListItem *next;

};

CoList.cpp 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 CoListItem.cpp

#include "CoListItem.h"

template <class T>
CoListItem<T>::CoListItem()
{
}


template <class T>
CoListItem<T>::~CoListItem()
{
}

and finally the main function:最后是主要的 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...如您所见,这是一个使用链表的非常简单的队列实现......

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. function 模板的定义(包括 class 模板的成员函数)必须在 .h 文件中,以便它们存在于使用它们的每个 cpp 文件中。 That's how templates work.这就是模板的工作方式。 You cant put the definitions into a cpp file.您不能将定义放入 cpp 文件中。 Technically, there is an export keyword which enables this but since almost no implementation supported it it was removed in the new standard.从技术上讲,有一个export关键字可以实现这一点,但由于几乎没有实现支持它,它在新标准中被删除。

Read this: The inclusion model阅读:包含 model

template definitions should be visible to the code which is using it. template定义应该对使用它的代码可见。 For that,为了那个原因,

  1. Put all the definitions in ".h" file将所有定义放在“.h”文件中
  2. Put the definitions in ".cpp" file (for the code separation) and #include that ".cpp" file将定义放在“.cpp”文件中(用于代码分离)并#include那个“.cpp”文件

For example, in your case you can #include "CoList.cpp" instead of "CoList.h" .例如,在您的情况下,您可以#include "CoList.cpp"而不是"CoList.h" And so on.等等。

This is straight from Nicolai Josutis's legendary book,这直接来自Nicolai Josutis 的传奇书籍,

C++ Templates: A complete Guide C++ 模板:完整指南

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.发现无效调用,例如不受支持的 function 调用。

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.当 function 模板以触发实例化的方式使用时,编译器将(在某些时候)需要查看该模板定义。 This breaks the usual compile and link distinction for functions, when declaration of function is sufficient to compile the its use.这打破了函数的通常编译和链接区别,当 function 的声明足以编译其使用时。


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.因此,对于模板,声明和定义应保存在同一个 header 文件中,以便它们在使用它们的每个 cpp 中可见。

Consider a template function that takes T and performs modulus (%), or a simple addition (+) for that matter.考虑一个模板 function,它采用 T 并执行模数 (%),或就此而言的简单加法 (+)。

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

You see NO ERROR in this code.您在此代码中看到 NO ERROR。 Alright.好吧。 When I pass two ints it gets compiled:当我传递两个整数时,它会被编译:

GetT(10,20);

But when I pass float/double it WONT compile:但是当我通过 float/double 时,它不会编译:

GetT(10.6, 20.5);

Compiler will emit: error C2296: '%': illegal, left operand has type 'double' and other related errors.编译器将发出: error C2296: '%': illegal, left operand has type 'double'和其他相关错误。 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.在您的情况下,CPP 只不过是编译器忽略的文本文件 - 全部。

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 + .话虽如此,当我使用 operator +而不是 operator %时,它将适用于所有基本数据类型,但不适用于缺少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.在某些情况下,编译器和 linker 一起工作以减少最终二进制代码的大小,当他们看到某些代码是重复的并且对于所有/几种数据类型都相同时。 But that's a different case.但那是另一回事。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM