Sign in to follow this  
RonHiler

Trouble with Templated Function

Recommended Posts

Hey guys, I'm having a little trouble with a templated function, and I could use some advice. This function has to do with my memory manager, which I nearly have finished. Here is the testing routine. I think this is pretty self-explanatory as to what it is meant to do:
//---------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
	{
	unsigned int Block1, Block2, Block3;
	int TestInt;
	float TestFloat;
	struct MyStruct{int TestInt; float TestFloat;} TestStruct;
	
	MemoryMgr.CreatePool("EnginePool1");
	Block1 = MemoryMgr.CreateBlock("EnginePool1", sizeof(int));
	Block2 = MemoryMgr.CreateBlock("EnginePool1", sizeof(float));
	Block3 = MemoryMgr.CreateBlock("EnginePool1", sizeof(TestStruct));
	
	TestInt = 23;
	TestFloat = 8.12f;
	TestStruct.TestInt = 12;
	TestStruct.TestFloat = 3.14f;
	
	MemoryMgr.WriteBlock("EnginePool1", Block1, &TestInt, sizeof(TestInt));
	MemoryMgr.WriteBlock("EnginePool1", Block2, &TestFloat, sizeof(TestFloat));
	MemoryMgr.WriteBlock("EnginePool1", Block3, &TestStruct, sizeof(TestStruct));

	MemoryMgr.WriteBlock("EnginePool1", Block1, 12, sizeof(int), 0);
	MemoryMgr.WriteBlock("EnginePool1", Block2, 7.345f, sizeof(float), 0);

	return 0;
	}
Ignore the CreatePool and CreateBlocks. Those work fine. What I'm interested in is getting the WriteBlocks to work. As you can see, I would like to get the routine to either take a reference or an actual value and store it in the block. This would be the most flexible behavior for the client of the memory manager class. I wrote a couple of functions to handle the pass by reference:
void WriteBlock(char *PoolName, unsigned int BlockHandle, void *Data, size_t ElementSize, unsigned short ArrayIndex=0);
void WriteBlock(unsigned int PoolHandle, unsigned int BlockHandle, void *Data, size_t ElementSize, unsigned short ArrayIndex=0);
Okay? This works fine. However, to handle the pass by value, I tried to add a templated function:
template <class AType> void WriteBlock(char *PoolName, unsigned int BlockHandle, AType Data, size_t ElementSize, unsigned short ArrayIndex);
Here is the issue. Everything works okay unless I specifiy a value for that defaulted argument (ArrayIndex) in the "pass by reference" style call, like such: MemoryMgr.WriteBlock("EnginePool1", Block1, &TestInt, sizeof(TestInt), 0); Instead of calling the first function, it is overloading the templated function (as an int* in this case), which was not my intent, and the problem is I can't use one function to handle both a pass by reference and a pass by value (they need different functionality). I'm not really sure how to handle this, and would appreciate any advice. [EDIT: I suppose I could just not use a templated function for the pass by values, and simply define a bunch of overloaded routines, like such:
void WriteBlock(char *PoolName, unsigned int BlockHandle, int Data, unsigned short ArrayIndex=0);
void WriteBlock(char *PoolName, unsigned int BlockHandle, float Data, unsigned short ArrayIndex=0);
void WriteBlock(char *PoolName, unsigned int BlockHandle, double Data, unsigned short ArrayIndex=0);
//etc
One advantage is that I could then specify a default value for ArrayIndex (which 9 times out of 10 the client will want to be 0). But that's a lot of code duplication. It seems like a template is the way to go here, but I can't seem to figure out how to get it to work the way I want.]

Share this post


Link to post
Share on other sites
Try
template <class AType> void WriteBlock(char *PoolName, unsigned int BlockHandle, AType* Data, size_t ElementSize, unsigned short ArrayIndex);

and
template <class AType> void WriteBlock(char *PoolName, unsigned int BlockHandle, AType& Data, size_t ElementSize, unsigned short ArrayIndex);

note the AType* and &



Share this post


Link to post
Share on other sites
Quote:
MemoryMgr.WriteBlock("EnginePool1", Block1, &TestInt, sizeof(TestInt), 0);

Instead of calling the first function, it is overloading the templated function (as an int* in this case), which was not my intent

Which is correct, you are passing a pointer to int. That was the intent specified in the above code. &X takes pointer to X.

Why are you passing sizeof() as argument. It can always be determined at compile type using sizeof(AType).

Quote:
I suppose I could just not use a templated function for the pass by values, and simply define a bunch of overloaded routines, like such:


template < class T > void write(void * dst, T & t)  {}
template < class T > void write(void * dst, const T & t) {}
template < class T > void write(void * dst, T * t) {}

int main(int argc, char **argv) {
int i;
write(0, i);
write(0, 44);
write(0, &i);
}

This is all that is needed. Pass by value isn't needed, or it would require overloading of concrete types.


Passing size of also doesn't make much sense, since size can always be determined from sizeof(T).

Share this post


Link to post
Share on other sites
Quote:
Original post by Makaan
Try
template <class AType> void WriteBlock(char *PoolName, unsigned int BlockHandle, AType* Data, size_t ElementSize, unsigned short ArrayIndex);

and
template <class AType> void WriteBlock(char *PoolName, unsigned int BlockHandle, AType& Data, size_t ElementSize, unsigned short ArrayIndex);

note the AType* and &


D'oh! Why didn't I see that? Of course, take the reference part out of the template. Duh. Thanks for pointing that out. That works perfect. [Not to nitpick, but just in case anyone else sees this thread and tries it, the second template actually needs to remove the & in order to receive a pass by value, I'm sure it was just a typo].

Share this post


Link to post
Share on other sites
Quote:
Original post by RonHiler

D'oh! Why didn't I see that? Of course, take the reference part out of the template. Duh. Thanks for pointing that out. That works perfect. [Not to nitpick, but just in case anyone else sees this thread and tries it, the second template actually needs to remove the & in order to receive a pass by value, I'm sure it was just a typo].


If you add pass by value, the call becomes ambiguous.
foo(i) could be pass by value or pass by reference - compiler cannot determine the intent.

Three cases are needed - pass by reference (to modify the argument), pass by const reference (for literals) and pointer argument.

Share this post


Link to post
Share on other sites
Quote:
Original post by Antheus
If you add pass by value, the call becomes ambiguous.
foo(i) could be pass by value or pass by reference - compiler cannot determine the intent.

Three cases are needed - pass by reference (to modify the argument), pass by const reference (for literals) and pointer argument.


Ah, right, I see what you mean. I'm working on it. And you are right, I don't need to pass the size. That was a bit of a holdover from the first pass. I'm taking it out.

Thanks much, guys. I appreciate the advice.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this