Skip to main content
GameDev.net gamedev.net
🔒 Locked

Templated Function within Templated Class

Started by Erzengeldeslichtes Jul 5, 2004 at 1:47 PM 16 replies 1.1k views
Original Post
Erzengeldeslichtes
Erzengeldeslichtes
I have a templated class that holds a pointer of the templated type, but I need to be able to cast that pointer into another template of the class. However, using visual C++ 6.0 I get either a compiler error saying that I can't use a class name as an expression, or that it can't figure out what I want on its own.

template<class T>
class Pointer
{
protected:
	T* m_Held;
	unsigned int* RefCount;
	void Add()
	{
		if(RefCount)
		{
			++*RefCount;
		}
		else
		{
			RefCount = new unsigned int(1);
		}
	}
	void Release()
	{
		if(RefCount)
		{
			--*RefCount;
			if(*RefCount == 0)
			{
				delete RefCount;
				delete m_Held;
			}
		}
	}
	Pointer(T* Obj, unsigned int* Count) : m_Held(Obj), RefCount(Count)
	{
		Add();
	}
public:
	Pointer(T* Obj) : m_Held(Obj), RefCount(0)
	{
		Add();
	}
	Pointer(const Pointer& rs) : m_Held(rs.m_Held), RefCount(rs.RefCount)
	{
	}
	~Pointer()
	{
		Release();
	}
	Pointer& operator=(const Pointer& rs)
	{
		Release();
		m_Held = rs.m_Held;
		RefCount = rs.RefCount;
		Add();
	}
	operator bool()
	{
		return m_Held != 0;
	}
	T* operator ->()
	{
		return m_Held;
	}
	template<class N>
	Pointer<N> Cast()
	{
		return Pointer<N>(dynamic_cast<N*>(m_Held), RefCount);
	}
};
class BaseObj;
class DerivObj : public BaseObj;
void main()
{
	Pointer<BaseObj> Blah(new DerivObj);
//I would think this would work:
	Pointer<DerivObj> Dude(Blah.Cast<DerivObj>());
//But I get C2275: 'DerivObj' : illegal use of this type as an expression
//So, just to try everything, I try taking that out:
	Pointer<DerivObj> Dude(Blah.Cast());
//And I get C2738 : 'class Pointer<T> __thiscall Pointer<class BaseObj>::Cast(void)' : could not deduce template argument for 'N'
//Yeah, didn't think it would work.
}
So... what the heck? What am I doing wrong?
----Erzengel des Lichtes光の大天使Archangel of LightEverything has a use. You must know that use, and when to properly use the effects.♀≈♂?
fallenang3l
fallenang3l
I haven't really looked at your code but I will tell you that VC++ 6.0 is notoriously bad with templates. Try compiling it on Borland's free compiler, g++ or something else that's standard compliant.
Ekim_Gram
Ekim_Gram
Quote:
Original post by fallenang3l
I haven't really looked at your code but I will tell you that VC++ 6.0 is notoriously bad with templates. Try compiling it on Borland's free compiler, g++ or something else that's standard compliant.


He's quite correct about VC++ 6.0 not being good with templates. If you are pretty serious about programming, go buy the standard edition of VC++.NET or use a different compiler.

Also, would you be so kind to tell use exactly where your getting these errors?
Erzengeldeslichtes
Erzengeldeslichtes
At the very bottom of the source code I gave above has the comments noting which lines give which errors and the exact error.

As for getting .net, I'd love to, but it's US$100 that I don't have. I'm trying that beta for 2005 express now...

Edit: Just tried with 2005 enterprise and now I'm getting "error C2065: 'DerivObj' : undeclared identifier" when I do Blah.Cast();, followed by a "error C2783: 'Pointer Pointer::Cast(void)' : could not deduce template argument for 'N'"

So it doesn't seem to like:
template<class T>class Pointer{//has lots of other infopublic:template<class N>Pointer<N> Cast(){//does the cast}};void main(){Pointer<SomeType> Blah(new DerivType);//Doesn't like this:Blah.Cast<DerivType>();}


[Edited by - Erzengeldeslichtes on July 5, 2004 3:55:02 PM]
----Erzengel des Lichtes光の大天使Archangel of LightEverything has a use. You must know that use, and when to properly use the effects.♀≈♂?
Erzengeldeslichtes
Erzengeldeslichtes
Well, I fixed it by making it a constructor instead of a seperate function, though I had to add in a method of accessing the held data (apparently Pointer and Pointer are different classes, so they can't access each others member variables and can not be made friends.)

Now I need a way to make all templates friends of each other... Can't do Template friend Pointer;, nor can I just do friend Pointer; (that means I'm a friend of myself...)

[Edited by - Erzengeldeslichtes on July 5, 2004 4:24:38 PM]
----Erzengel des Lichtes光の大天使Archangel of LightEverything has a use. You must know that use, and when to properly use the effects.♀≈♂?
snk_kid
snk_kid
Hi now that you have a more standard compliant compiler instead of making a cast member function, a templated copy constructor would be preferable e.g.

template< typename T >class ptr {   typedef unsigned int size_type;   T* _p;   size_type ref_count;public:  T* get() const { return _p; }  template< typename U >  ptr(const ptr& p): _p(0), ref_count(p.ref_count) {     _p = dynamic_cast<T*>(p.get());     //to do add reference count etc  }};


Although i think using boost smart pointers in particular intrusive_ptr type is the way to go.
Erzengeldeslichtes
Erzengeldeslichtes
Quote:
Original post by snk_kid
Hi now that you have a more standard compliant compiler instead of making a cast member function, a templated copy constructor would be preferable e.g.

*** Source Snippet Removed ***

Although i think using boost smart pointers in particular intrusive_ptr type is the way to go.


Doesn't work:
error C2248: ptr::ref_count' : cannot access private member declared in class ptr'

I want to avoid using libraries that don't come with the compiler.
----Erzengel des Lichtes光の大天使Archangel of LightEverything has a use. You must know that use, and when to properly use the effects.♀≈♂?
snk_kid
snk_kid
Quote:
Original post by Erzengeldeslichtes
Quote:
Original post by snk_kid
Hi now that you have a more standard compliant compiler instead of making a cast member function, a templated copy constructor would be preferable e.g.

*** Source Snippet Removed ***

Although i think using boost smart pointers in particular intrusive_ptr type is the way to go.


Doesn't work:
error C2248: ptr::ref_count' : cannot access private member declared in class ptr'

I want to avoid using libraries that don't come with the compiler.


I didn't try to compile that code, just a add an inline member function to get the reference counter e.g.

so with the above modified this should work.

template< typename T >class ptr {   typedef unsigned int size_type;   T* _p;   size_type ref_count;public:  size_type get_ref_count() const { return ref_count; }  T* get() const { return _p; }  template< typename U >  ptr(const ptr& p): _p(0), ref_count(p.get_ref_count()) {     _p = dynamic_cast<T*>(p.get());     //to do add reference count etc  }};


boost libraries are as close as you can get to standard libraries believe me they are very useful.
Erzengeldeslichtes
Erzengeldeslichtes
Okay, that adding a public accessor is what I did (wish I didn't have to.)

Now .net is driving me insane. It gives me a bunch of warnings about deprecated functions. It gave me 2 errors about libraries it couldn't find (so I removed them from the list). Now it gives me an error about MessageBoxA being an unresolved external. Why does .net complain so much? VC++ 6 worked perfectly fine...

I'm going to go return to beating my head on a wall.
----Erzengel des Lichtes光の大天使Archangel of LightEverything has a use. You must know that use, and when to properly use the effects.♀≈♂?
snk_kid
snk_kid
Quote:
Original post by Erzengeldeslichtes
Okay, that adding a public accessor is what I did (wish I didn't have to.)

Don't worry when defining a member function inside a class it's implicitly inlined (if possible) and as it's only getting a member. The compiler should easly inline & remove the overhead.

Quote:
Original post by Erzengeldeslichtes
Now .net is driving me insane. It gives me a bunch of warnings about deprecated functions. It gave me 2 errors about libraries it couldn't find (so I removed them from the list). Now it gives me an error about MessageBoxA being an unresolved external. Why does .net complain so much? VC++ 6 worked perfectly fine...

I'm going to go return to beating my head on a wall.


Because VC++ 6.0 was released as C++ was standardized so its support for C++ is poor, it didn't support templates fully, its STL imp was buggy, it supported deprecated headers. There are service packs that can fix most issues.

If your using the latest version of VC++ .NET then deprecated headers have been completely taken out, so all standard C++ libraries do not have .h extension e.g. #include is mean't to be #include, all standard C library headers (in standard C++ only) have a c appended to the front e.g. #include this is the standard. VC++ .NET is much more standard compliant.
Erzengeldeslichtes
Erzengeldeslichtes
Yeah, I figured they had taken out the .h when it was giving me errors that it couldn't find , so I switched it to . It then said it couldn't find , nor . I thought windows.h was included in the default headers of the compiler, but apparently not, so I went ahead and put in the directories for the Windows SDK. Now it just complains that MessageBoxA is an unresolved external. Searching the help I can't even find a MessageBox function at all, only a MessageBox class.

As for the deprecated, it's talking about wcsncpy, strncpy, fopen, that sort of thing, but since it's only giving warnings and not errors I'd guess I can still use them.
----Erzengel des Lichtes光の大天使Archangel of LightEverything has a use. You must know that use, and when to properly use the effects.♀≈♂?
snk_kid
snk_kid
Quote:
Original post by Erzengeldeslichtes
Yeah, I figured they had taken out the .h when it was giving me errors that it couldn't find , so I switched it to . It then said it couldn't find , nor . I thought windows.h was included in the default headers of the compiler, but apparently not, so I went ahead and put in the directories for the Windows SDK. Now it just complains that MessageBoxA is an unresolved external. Searching the help I can't even find a MessageBox function at all, only a MessageBox class.


windows.h is win32 header so its not part of the C++ standard so it's still #include. Sounds like your using VC++ .NET 2005 express edition which is actually using a new C++ language, supports almost complete of the ISO C++ but added some new language features to work better in a managed enviroment. For win32 applications you need to have have downloaded the platform SDK, then select File -> New -> Project -> Select win32 -> Select win32 console app -> Next -> select Windows application -> finish. Once you have that setup then you not only need to add the include directory to include path but you need to add the library directory to the lib path aswell thats why your getting link errors.

Quote:
Original post by Erzengeldeslichtes
As for the deprecated, it's talking about wcsncpy, strncpy, fopen, that sort of thing, but since it's only giving warnings and not errors I'd guess I can still use them.


What headers are you including and what warnings are you getting?
Erzengeldeslichtes
Erzengeldeslichtes
The includes I'm using are
//string.h#include <tchar.h>#include <cstdio>#include <cmath>#include <cstdlib>//log.h#include "string.h"#include <windows.h>#include <ctime>



Oig, so now it even gives me the stdafx.h, stdafx.cpp, readme.txt (which informs that stdafx is for a precompiled header, but neglects to inform me as to why I would want a precompiled header...) and (projectname).cpp. I liked an empty project, I don't want you shoving stuff in my project, I'll put what I want in it.
----Erzengel des Lichtes光の大天使Archangel of LightEverything has a use. You must know that use, and when to properly use the effects.♀≈♂?
snk_kid
snk_kid
Sorry i just remembered that VC++ only took out .h files in iostreams library. You can create an empty project aswell.
Erzengeldeslichtes
Erzengeldeslichtes
Okay, I see that now... Though why they call it a console application (win32) when I can make a Windows App, Console App, DLL, or Static Library is beyond me...

Even after changing them all to cstdio or cstring, it still calls the functions from stdio.h, because that's where it says the deprecations are declared at, even though none of my files include stdio.h or string.h.

And even putting my code into a new, empty win32 console "solution", MessageBoxA is still unresolved external (and all directories: include, source, library, and executable are set up for the windows SDK)
----Erzengel des Lichtes光の大天使Archangel of LightEverything has a use. You must know that use, and when to properly use the effects.♀≈♂?
psykr
psykr
I'm not sure if this is implicitly included in your Cast() function, but in the smart pointer class presented in (More?) Effective C++, there's an implicit operator that lets you cast the held pointer up the class hierarchy as appropriate:
template< typename T >class smart_ptr {	...public:	template< typename U >	operator smart_ptr () {		return smart_ptr( HeldPointer );	}};

Try including that in your smart pointer class; I couldn't decipher how you use it (I'm really tired), so I apologize if you already have this in there.

edit: Hm, don't know if you're still having problems, but this isn't anything particularly fancy with templates, and I get it to compile on VC6 just fine.
Erzengeldeslichtes
Erzengeldeslichtes
No, I've fixed the problems with my 'smart pointer', now I'm just trying to figure out .Net.

I've taken out the code that could possibly use the message box, mainly because I realized I was using Win32 Console, can I really create a message box from a console application? I don't think so. Why did Visual C++ 6.0 let me compile even though I might have called it? Perhaps because it optimized away the code since it checked a variable that was constant. Eh, whatever the reason, my brain isn't hurting so much... for now. I'll see if my brain explodes when I try to convert over my D3D application...
----Erzengel des Lichtes光の大天使Archangel of LightEverything has a use. You must know that use, and when to properly use the effects.♀≈♂?

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.