Jump to content
  • Advertisement
Sign in to follow this  
ZedFx

Template substantiation

This topic is 4707 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

Cast your eyes over the following.
template < typename T > struct tMemory
{
	static void Allocate(T * & Memory, unsigned int Count);
	static void Free(T * & Memory);

};

template < typename T > void tMemory< T >::Allocate(T * & Memory, unsigned int Count)
{

	try
	{
		Memory = new T[Count];

	}

	catch (...)
	{
		Err_OutOfMemory.Raise(); // this is defined elsewhere (do not worry about it)

		goto error;

	}

	return;

error:

	// display error message

	return;

}

template < typename T > void tMemory< T >::Free(T * & Memory)
{
	delete [] Memory;

}

typedef int (* cFunc)(void *);

class cTest
{
public:

	// rest of class

	void CreateFunc(unsigned int Count);

	// rest of class

private:

	tMemory< cFunc > m_Memory;
	cFunc * m_MemoryPtr;

	// other member variables

	void DestroyFunc();

};

void cTest::CreateFunc(unsigned int Count)
{
	m_Memory.Allocate(m_MemoryPtr, Count);

}


void cTest::DestroyFunc()
{
	m_Memory.Free(m_MemoryPtr);

}



I am getting linker errors where static void tMemory< int (*)(void *) >::Allocate(int (** &)(void *), unsigned int); static void tMemory< int (*)(void *) >::Free(int (** &)(void *)); are both unresolved.... I have no idea why, anyone else have any ideas ? EDIT: sloppy coding.. (fixed) [Edited by - ZedFx on August 31, 2005 5:18:42 PM]

Share this post


Link to post
Share on other sites
Advertisement
Once I change the function prototype of DestroyFunc so that it matches with the definition, it compiles and links fine for me on MSVC 2003. The template functions are all defined in headers or are otherwise available right?

Share this post


Link to post
Share on other sites
To toss out some random possibilities:

1) Try placing the static keyword with the function declerations as well. I don't think it's needed (it may not even be valid) but it's worth a shot.
Given SiCrane's response, I apparently was correct in thinking it wasn't needed.

2) Are the functions declared within a source file? Currently, most compilers require the functions be declared where they're "visible" for proper instantiation, or manually instantiated. E.g.:

Option 1: Visible decleration for automatic instantiation (multiple files not required)
//tmemory.hpp
#ifndef IG_TMEMORY
#define IG_TMEMORY

template < typename T > struct tMemory {
...
};

#include "tmemory.impl"
#endif //ndef IG_TMEMORY

//tmemory.impl
template < typename T > void tMemory< T >::Allocate(T * & Memory , unsigned int Count ) {
...
}
...


Option 2: Manual instantiation
//tmemory.hpp
#ifndef IG_TMEMORY
#define IG_TMEMORY

template < typename T > struct tMemory {
...
};

//Not including their actual implementation:
//#include "tmemory.impl"
#endif //ndef IG_TMEMORY

//tmemory.impl
template < typename T > void tMemory< T >::Allocate(T * & Memory , unsigned int Count ) {
...
}
...

//tmemory.cc
#include "tmemory.impl"

template tMemory<int>;
template tMemory<char>;
template tMemory<int (*)(void *)>;
...


Option 3: Use the export template feature
This isn't available on most compilers. However, see Comeau C++ Export Overview documentaiton for that, for the, like, one compiler that does that. Comeau, in case you couldn't guess :-).

Share this post


Link to post
Share on other sites
template < typename T > struct tMemory
is defined in tMemory.h

template < typename T > void tMemory< T >::Allocate(T * & Memory, unsigned int Count)
and
template < typename T > void tMemory< T >::Free(T * & Memory)
are defined in tMemory.cpp which includes tMemory.h

typedef int (* cFunc)(void *);
is defined in cFunc.h

class cTest
is defined in cTest.h which includes tMemory.h

void cTest::CreateFunc(unsigned int Count)
and
void cTest::DestroyFunc()
are defined in cTest.cpp which include cTest.h (and implicitly tMemory.h)

That is how I have it structured essentially.

Share this post


Link to post
Share on other sites
Quote:
Original post by ZedFx
template < typename T > void tMemory< T >::Allocate(T * & Memory, unsigned int Count)
and
template < typename T > void tMemory< T >::Free(T * & Memory)
are defined in tMemory.cpp which includes tMemory.h


Here's the problem. Unless your compiler supports the export keyword, and I'm willing to bet that yours doesn't, then you can't put the definition of a template in a separate source file without explicit instantiation for specific types. Without explicit instantiation, the complete definition of the template needs to be available at point of instantiation, which means, in effect, that the definition needs to go into the header. (Or an inline file of some sort, etc.)

For more details see these articles: "Export" Restrictions, Part 1 and "Export" Restrictions, Part 2.

Share this post


Link to post
Share on other sites
Just as a friendly addendum, you'll probably want to avoid code of the sort that you wrote below:


catch (...)
{
Err_OutOfMemory.Raise(); // this is defined elsewhere (do not worry about it)
goto error;
}
return;
error:
// display error message
return;


Using goto statements is in general frowned upon, but escaping from a catch block is definitely evil. Also evil is using the dreaded ellipsis construct in a catch expression. It's pretty clear that you really wanted to catch some kind of out of memory exception ("Err_OutOfMemory.Raise()") in that catch block, so that's what you should be catching instead.

Share this post


Link to post
Share on other sites
Quote:
Original post by kSquared
Also evil is using the dreaded ellipsis construct in a catch expression.

That much I definately would not call evil, even though in this case, considering the body of the catch, it is.

Often times, especially in templates, you may need to peform some type of memory deallocation, other cleanup, or something else when any exception is thrown, usually prior to a rethrow (since you often can't handle an exception when you don't even know what it is). You may not know what type of exceptions can be thrown, for instance, because you are in a template and the exception is thrown by something dependent on one or more template arguments, such as in this case. Note that here, there is the dynamic allocation of template argument T in the try expression. His catch assumes that only an out of memory exception can be thrown (since he is always calling Err_OutOfMemory.Raise()). Realistically, however, any type of exception can be thrown. This is because the constructor call on one of the array elements may throw an exception for any reason. You don't know what types are possible (and generally shouldn't care) since that information is dependent on T. Such an error should probably still be caught, partially handled (maybe for logging, releasing things not accounted for by RAII, etc.), and then probably rethrown. Using ... in a catch statement is really the best way to handle such a situation.

Share this post


Link to post
Share on other sites
The best solution here would be to have two catch blocks, of course. Catch the out-of-memory condition explicitly (Though it's actually fairly difficult to get new to throw. It calls the new handler and this path usually leads to abort().) and catch every other kind of exception with ... I usually prefer to catch exceptions derived from std::exception in another seperate block, as I know these have a loggable what() function. All exceptions should be derived from this anyway.

Share this post


Link to post
Share on other sites
Quote:
Original post by Polymorphic OOP
Quote:
Original post by kSquared
Also evil is using the dreaded ellipsis construct in a catch expression.

That much I definately would not call evil, even though in this case, considering the body of the catch, it is.

That's what I really meant to say (see the following sentence of my previous post). :)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • 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!