Jump to content
  • Advertisement

Archived

This topic is now archived and is closed to further replies.

Normie

Templated Classes...Oy.

This topic is 6013 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
To defined template class member functions you must write them like so:

template<typename T>
class SomeClass
{
    public:
        SomeClass();
       ~SomeClass();

        T GetSomething();
};

template<typename T>
SomeClass<T>::SomeClass()
{
    // code goes here.
}

template<typename T>
T SomeClass<T>::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

Share this post


Link to post
Share on other sites
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!

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
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

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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!

Share this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!