17

[[UPDATE]] -> If I #include "Queue.cpp" in my program.cpp, it works just fine. This shouldn't be necessary, right?

Hey all -- I'm using Visual Studio 2010 and having trouble linking a quick-and-dirty Queue implementation. I started with an empty Win32 Console Application, and all files are present in the project. For verbosity, here's the complete code to duplicate my error. I realize some of the code may, in fact, be wrong. I haven't had a chance to test it yet because I haven't yet been able to link it.

Queue.hpp

#ifndef ERROR_CODE
#define ERROR_CODE
enum Error_Code
{
    Success,
    Underflow,
    Overflow
};
#endif // ERROR_CODE

#ifndef QUEUE
#define QUEUE
template<class T>
struct Queue_Node
{
    T data;
    Queue_Node *next;

    Queue_Node()
    {
        next = NULL;
    }
    Queue_Node(T pData)
    {
        data = pData;
        next = NULL;
    }
    Queue_Node(T pData, Queue_Node *pNext)
    {
        data = pData;
        next = pNext;
    }
};

template<class T>
class Queue
{
public:
    Queue();
    Error_Code Serve();
    Error_Code Append(T item);
    T Front();
    ~Queue();

private:
    void Rescursive_Destroy(Queue_Node<T> *entry);
    Queue_Node<T> *front, *rear;
};
#endif // QUEUE

Queue.cpp

#include "Queue.hpp"

template <class T>
Queue<T>::Queue()
{
    this->front = this->rear = NULL;
}

template<class T>
Error_Code Queue<T>::Serve()
{
    if(front == NULL)
        return Underflow;

    Queue_Node *temp = this->front;
    this->front = this->front->next;
    delete temp;
}

template<class T>
Error_Code Queue<T>::Append(T item)
{
    Queue_Node *temp = new Queue_Node(item);
    if(!temp)
        return Overflow;

    if(this->rear != NULL)
        this->rear->next = temp;
    this->rear = temp;

    return Success;
}

template<class T>
T Queue<T>::Front()
{
    if(this->front == NULL)
        return Underflow;
    return this->front->data;
}

template<class T>
Queue<T>::~Queue()
{
    this->Rescursive_Destroy(this->front);
}

template<class T>
void Queue<T>::Rescursive_Destroy(Queue_Node<T> *entry)
{
    if(entry != NULL)
    {
        this->Recursive_Destroy(entry->next);
        delete entry;
    }
}

program.cpp

#include "Queue.hpp"

int main()
{
    Queue<int> steve;
    return 0;
}

And the errors...

Error   1   error LNK2019: unresolved external symbol "public: __thiscall Queue<int>::~Queue<int>(void)" (??1?$Queue@H@@QAE@XZ) referenced in function _main    C:\[omitted]\Project2_2\Project2_2\program.obj  Project2_2
Error   2   error LNK2019: unresolved external symbol "public: __thiscall Queue<int>::Queue<int>(void)" (??0?$Queue@H@@QAE@XZ) referenced in function _main C:\[omitted]\Project2_2\Project2_2\program.obj  Project2_2
Squirrelsama
  • 5,480
  • 4
  • 28
  • 38
  • 2
    Just as general notes on the code; you don't need include guards for every class in a header, and doing that is a lot more likely to conflict. Rather, put one include guard around the entire header, based on the filename of that header. It's both standard practice and a lot less likely to run into other filenames. – Todd Gardner Sep 14 '10 at 02:49
  • Duplicate of [Linker Error LNK2019](http://stackoverflow.com/questions/3680312/linker-error-lnk2019) (This question gets asked about five times every week) – James McNellis Sep 14 '10 at 03:37

5 Answers5

25

Why don't you follow the "Inclusion Model"? I'd recommend you follow that model. The compiler needs to have access to the entire template definition (not just the signature) in order to generate code for each instantiation of the template, so you need to move the definitions of the functions to your header.

Note: In general most C++ compilers do not easily support the separate compilation model for templates.

Furthermore you need to read this.

Prasoon Saurav
  • 91,295
  • 49
  • 239
  • 345
6

An example for solving the error lnk2019:
It has to write #include "EXAMPLE.cpp" at the end of .h file

//header file codes
#pragma once
#ifndef EXAMPLE_H
#define EXAMPLE_H

template <class T>
class EXAMPLE
{

//class members
void Fnuction1();

};


//write this
#include "EXAMPLE.cpp"


#endif
//----------------------------------------------

In the .cpp file do as following

//precompile header
#include "stdafx.h"
#pragma once
#ifndef _EXAMPLE_CPP_
#define _EXAMPLE_CPP_

template <class T> 
void EXAMPLE<T>::Fnuction1()
{
 //codes
}

#endif
//-----------------------------------------------
SaeidMo7
  • 1,214
  • 15
  • 22
5

All template code need to be accessible during compilation. Move the Queue.cpp implementation details into the header so that they are available.

skimobear
  • 1,188
  • 10
  • 12
4

The linker errors are because it sees the header files for Queue.hpp, but doesn't see the definitions of the functions. This is because it is a template class, and for C++, the definitions of templates must be in the header file (there are a few other options, but that is the easiest solution). Move the defintions of the functions from Queue.cpp to Queue.hpp and it should compile.

Todd Gardner
  • 13,313
  • 39
  • 51
  • Yes, all files are included. If I, for example, omit a semicolon in Queue.cpp, the project doesn't get to the linking process because it suddenly fails to compile. – Squirrelsama Sep 14 '10 at 02:38
  • I didn't notice it was a template during my first pass; that explains the error. – Todd Gardner Sep 14 '10 at 02:39
  • Why do templates cause this error? Also... [[UPDATE]] -> If I #include "Queue.cpp" in my program.cpp, it works just fine. This shouldn't be necessary, right? – Squirrelsama Sep 14 '10 at 02:41
  • See answers like this one: http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file – Todd Gardner Sep 14 '10 at 02:45
4

If you have:

template <typename T>
void foo();

And you do:

foo<int>();

The compiler needs to generate (instantiate) that function. But it can't do that unless the function definition is visible at the point of instantiation.

This means template definitions needs to be included, in some way, in the header. (You can include the .cpp at the end of the header, or just provide the definitions inline.)

GManNickG
  • 494,350
  • 52
  • 494
  • 543