Template substantiation

Started by
10 comments, last by antareus 18 years, 7 months ago
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]
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?
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_TMEMORYtemplate < typename T > struct tMemory {    ...};#include "tmemory.impl"#endif //ndef IG_TMEMORY//tmemory.impltemplate < typename T > void tMemory< T >::Allocate(T * & Memory , unsigned int Count ) {    ...}...


Option 2: Manual instantiation
//tmemory.hpp#ifndef IG_TMEMORY#define IG_TMEMORYtemplate < typename T > struct tMemory {    ...};//Not including their actual implementation://#include "tmemory.impl"#endif //ndef IG_TMEMORY//tmemory.impltemplate < 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 :-).
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.
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.
Thanks. Damn C++ is finicky... I need a new language ;-)
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.
- k2"Choose a job you love, and you'll never have to work a day in your life." — Confucius"Logic will get you from A to B. Imagination will get you everywhere." — Albert Einstein"Money is the most egalitarian force in society. It confers power on whoever holds it." — Roger Starr{General Programming Forum FAQ} | {Blog/Journal} | {[email=kkaitan at gmail dot com]e-mail me[/email]} | {excellent webhosting}
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.
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.
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). :)
- k2"Choose a job you love, and you'll never have to work a day in your life." — Confucius"Logic will get you from A to B. Imagination will get you everywhere." — Albert Einstein"Money is the most egalitarian force in society. It confers power on whoever holds it." — Roger Starr{General Programming Forum FAQ} | {Blog/Journal} | {[email=kkaitan at gmail dot com]e-mail me[/email]} | {excellent webhosting}

This topic is closed to new replies.

Advertisement