Templated Classes...Oy.

Started by
20 comments, last by Normie 22 years, 2 months ago
I'm trying to make a templated linked list class (just to see if I can). The class I have works fine if I have all of the function bodies in the class, but if I put the bodies outside of the class, I get linker errors out of the wazoo. Here's my class:
  
template<class Data>
struct LISTNODE
{
	Data data;
	LISTNODE<Data>* pPrev;
	LISTNODE<Data>* pNext;
};

template<class Data>
class CLinkedList  
{
public:
	CLinkedList()
	{
		m_pList = NULL;
		m_pFirst = NULL;
		m_pLast = NULL;

		m_numRecords = 0;
	}

	virtual ~CLinkedList()
	{
		LISTNODE<Data>* tempNode = NULL;

		m_pList = m_pFirst;

		do
		{
			if (m_pList)
			{
				tempNode = m_pList->pNext;
				delete m_pList;
			}
			m_pList = tempNode;
		} while (tempNode);
	}

	void AddItem(const Data& data)
	{
		if (!m_pFirst) // if this is the first node

		{
			m_pList = new LISTNODE<Data>; // make the first node

			m_pFirst = m_pLast = m_pList; // set all of the pointers

			m_pList->pNext = m_pList->pPrev = NULL; // Ditto

			m_pList->data = data;
		}
		else
		{
			LISTNODE<Data>* tempNode;

			tempNode = m_pLast;
			m_pLast->pNext = new LISTNODE<Data>;
			m_pLast = m_pLast->pNext;
			m_pLast->data = data;
			m_pLast->pPrev = tempNode;
			m_pLast->pNext = NULL;
			tempNode->pNext = m_pLast;
		}
		m_numRecords++;
	}

	Data operator[](int index)
	{
		LISTNODE<Data>* tempNode;
		int i;

		if (index < 0 || index > m_numRecords - 1)
			return NULL;

		tempNode = m_pList = m_pFirst;

		for (i = 0; i < index; i++)
		{
			tempNode = tempNode->pNext;		
		}

		return tempNode->data;
	}
private:
	LISTNODE<Data>* m_pList;
	LISTNODE<Data>* m_pFirst;
	LISTNODE<Data>* m_pLast;

	int m_numRecords;
};
  
I hate the idea of having all of the code present in the class definition, so if anyone can tell me why pulling the function bodies out of the function results in linker errors, I'd really appreciate it. -Normie --EDIT--Oh, that should be "template above the struct and the class.--/EDIT-- Edited by - Normie on January 29, 2002 11:37:48 AM Grr... the template is "class Data." Why did it remove the brackets???? Edited by - Normie on January 29, 2002 11:38:58 AM Edited by - Normie on January 29, 2002 11:39:59 AM [edit: changed code tags to source tags] Edited by - Magmai Kai Holmlor on January 30, 2002 1:30:05 AM
I am a devout follower of the"Lazy Programmer's Doctrime"(tm)...and I'm damned proud of it, too!-----"I came, I saw, I started makinggames." ... If you'll excuseme, I must resume my searchfor my long lost lobotomy stitches.
Advertisement
This is one of the big headaches I used to have with templates.

A template on its own does not generate any code - the compiler just ignores it. So when you try and use a CLinkedList< int > or whatever, the linker looks for a CLnkedList< int > in a .obj file, and finds nothing. Hence the lovely linker errors.

In order to resolve this, you need to specifically tell the compiler which versions of CLinkedList it needs, so it actually bothers to build them into a .obj file.

To do this, add this line of code into the CLinkedList header file...

              CLinkedList<int>;CLinkedList<float>;CLinkedList<CLinkedList<int>>; // linked list of linked lists!// etc....              


Simple, huh?

To be honest though, I find it easier to leave the implementation in the header file - this works because the cpp that includes the header file has all the information it needs to build the implementation itself - no need to link with a .obj file.


Edited by - Sandman on January 29, 2002 12:52:14 PM
To defined template class member functions you must write them like so:

template&lttypename T>
class SomeClass
{
   &nbsppublic:
       &nbspSomeClass();
       ~SomeClass();

       &nbspT GetSomething();
};

template&lttypename T>
SomeClass&ltT>::SomeClass()
{
    // code goes here.
}

template&lttypename T>
T SomeClass&ltT>::GetSomething()
{
    // code goes here
}

Now on the other hand you might mean putting the function bodies in a source file (.cpp file) which I'm not sure how to do (if it is even possible.)



Dire Wolf
www.digitalfiends.com

Edited by - Dire.Wolf on January 29, 2002 12:51:31 PM
[email=direwolf@digitalfiends.com]Dire Wolf[/email]
www.digitalfiends.com
it would suck ass to do that, sandman. it practically defeats the purpose of user templating.
quote:Original post by EvilCrap
it would suck ass to do that, sandman. it practically defeats the purpose of user templating.

No offense, but I''ve noticed that you seem to comment on things you don''t understand. What Sandman mentions is called explicit template instantiation (look it up), and is necessary if you wish to export a template class in precompiled (.lib/.dll/.so/.a) form. Which is generally why template classes are distributed as source code.

[ GDNet Start Here | GDNet Search Tool | GDNet FAQ | MS RTFM [MSDN] | SGI STL Docs | Google! ]
Thanks to Kylotan for the idea!
ok, so just to make sure I understand...there''s no way to put the source code in a .cpp file and still be able to use it (without specifically declaring the templatized data types)?

*Sigh* That _really_ sucks. :-(

-Normie
I am a devout follower of the"Lazy Programmer's Doctrime"(tm)...and I'm damned proud of it, too!-----"I came, I saw, I started makinggames." ... If you'll excuseme, I must resume my searchfor my long lost lobotomy stitches.
According to the C++ standard you can declare a template with the ''export'' keyword to tell the compiler to export the template-definition for later instantiation (when it needs to be instantiated in another module for example). AFAIK this is currently supported by very few compilers.
If want your code in the cpp file, you have to include *both* the .h & .cpp files every time OR put an #include "code.cpp" at the bottom of the header.

Alternatively, if you don''t mind having the definitions in the header but want to easily be able to read your class''s functions just do this:

template< typename DATA >
class C
{
public:
// suto functions prototypes:
/*
void Func(void); // all your functions here
*/

// ***************************************
// ***************************************
// actual functions:
void Func(void)
{
}

};

however if you do this you''ll have to remember to always update the suto functions section when you update actual functions'' parameters/return types
Dactylos: Does VC++6 support exporting? if it does, can you tell me how to do it in code? Also, will doing this cause any problems later?

Anonymous: Will that method cause any problems later?

-Normie
I am a devout follower of the"Lazy Programmer's Doctrime"(tm)...and I'm damned proud of it, too!-----"I came, I saw, I started makinggames." ... If you'll excuseme, I must resume my searchfor my long lost lobotomy stitches.
quote:Original post by Normie
Dactylos: Does VC++6 support exporting?

No. Neither does 7, IIRC.
quote:Anonymous: Will that method cause any problems later?

I know he meant "pseudo" rather than "suto" (hey, not everybody is a native English speaker!), but I don''t understand the technique or how it helps...

[ GDNet Start Here | GDNet Search Tool | GDNet FAQ | MS RTFM [MSDN] | SGI STL Docs | Google! ]
Thanks to Kylotan for the idea!

This topic is closed to new replies.

Advertisement