static const templates

Started by
7 comments, last by SiCrane 13 years, 6 months ago
I have a reference counted smart pointer called coreRef<>, and wanted to have a static const member that is effectively a NULL value, so I tried the following;
template < typename T >class coreRef{	public:		/// Constructors and Destructors		~coreRef(){			...		}				coreRef( const coreRef< T >& ref ): ptr( ref.ptr ){			...		}				explicit coreRef( T* val = NULL ): ptr( NULL ){			...		}				/// Overloaded operators		coreRef& operator = ( const coreRef<T> ref ){			...		}				T* operator -> () const {			...		}				// This is the line that's causing me problems		static const coreRef< T > null;		...}


I have an abstract class which acts as its own class factory, and to test it, I created a dummy class derived from it. However, when I tried
return coreRef<otherType>::null;

I keep getting undefined reference errors. What can I do to correct this?

[Edited by - webwraith on October 17, 2010 12:40:56 PM]
Advertisement
Static template member variables, like non-template static variables need to be defined in addition to be declared. In your case, the syntax looks like:
template <typename T> coreRef<T> coreRef<T>::null;

Like most template code it should go in the same header that the rest of your template class lives in.
You need to specify to the compiler where the static variable is defined , so for a normal class you would write in the .cpp file
var_type your_normal_class::your_static_var = some value;

at this point the variable is referenced.

Ok but you have a template class , so this messes up the problem ,
just write in the .h file , right under your class definition:

template <class T> coreRef< T >::null = whatever value;


i guess that because of the definition in the .h file there might be errors later if the variable is not const also.
The problem is that I declare the variable const (which I appear to have missed out in the OP, sorry about that, I'll change it now), and GCC/G++ complains that I haven't defined the value at the declaration site. I suppose I could have a private variable, then return a coreRef< T >& const (or with the const at the start, I always get its location mixed up) to the private variable.
Post a minimal, but complete, code sample that demonstrates your problem. Deleting stuff from your class as posted so that it compiles and using the suggested syntax produces code that links with g++ 4.3.4.
Right, the coreRef template is exactly as above, now that I've changed the 'null' variable. I'll post the full code to that as well later if you want to see it, but the function declarations should be good. The problem comes with the following;

Abstract IGraphics class:
class IGraphics{	protected:		static IGraphics* graphics;	public:		// use in the form "coreRef< IGraphics > grph = IGraphics::GetInterface< ConcreteGraphicsClass >();"		template < class T >		static coreRef< IGraphics > GetInterface(){			if( graphics == NULL ){				graphics = new T;			}			return coreRef< IGraphics >( graphics );		}		/// Note that the following GetXXX() functions will later be given arguments		virtual coreRef< IMesh > 		GetMesh() 		= 0;		// retrieves a mesh from the mesh manager		virtual coreRef< ITexture >		GetTexture() 	= 0;		// retrieves a texture from the texture manager		virtual coreRef< ITerrain >		GetTerrain() 	= 0;		// retrieves a terrain from the terrain manager};IGraphics* IGraphics::graphics = NULL;


and the derived class that keeps throwing errors, along with my testing main():
class dummy : public IGraphics{	public:				virtual coreRef< IMesh > 		GetMesh(){ return coreRef< IMesh >::null; }			// retrieves a mesh from the mesh manager		virtual coreRef< ITexture >		GetTexture(){ return coreRef< ITexture >::null; }	// retrieves a texture from the texture manager		virtual coreRef< ITerrain >		GetTerrain(){ return coreRef< ITerrain >::null; }	// retrieves a terrain from the terrain manager			protected:			private:		};int main(int argc, char **argv){	coreRef< IGraphics > graph = IGraphics::GetInterface< dummy >();	return 0;}


The errors are to do with the returns in class 'dummy'. For each one I get an 'Undefined reference to coreRef< x >::null', where 'x' is the class in question.

Currently, each of the IMesh, ITexture and ITerrain classes are stubs that have no code in them.
A complete code sample contains everything necessary to compile. Someone should be able to copy and paste from what you've posted and see the error you're complaining about. In this case, since you're complaining about a linker error the code you post should compile. What you've posted does not.
Right, well here we go:

main.cpp:
#include <iostream>#include "i_graphics.h"#include "core_ref.h"class dummy : public IGraphics{	public:				virtual coreRef< IMesh > 		GetMesh(){ return coreRef< IMesh >::null; }			// retrieves a mesh from the mesh manager		virtual coreRef< ITexture >		GetTexture(){ return coreRef< ITexture >::null; }	// retrieves a texture from the texture manager		virtual coreRef< ITerrain >		GetTerrain(){ return coreRef< ITerrain >::null; }	// retrieves a terrain from the terrain manager			protected:			private:		};int main(int argc, char **argv){	coreRef< IGraphics > graph = IGraphics::GetInterface< dummy >();	return 0;}


i_graphics.h:
#ifndef _CORE_GRAPHICS#define _CORE_GRAPHICS#include "i_mesh.h"#include "i_texture.h"#include "i_terrain.h"#include "core_ref.h"class IGraphics{	protected:		static IGraphics* graphics;	public:		// use in the form "IGraphics* grph = IGraphics::GetInterface< ConcreteGraphicsClass >();"		template < class T >		static coreRef< IGraphics > GetInterface(){			if( graphics == NULL ){				graphics = new T;			}			return coreRef< IGraphics >( graphics );		}		/// Note that the following GetXXX() functions will later be given arguments		virtual coreRef< IMesh > 		GetMesh() 		= 0;		// retrieves a mesh from the mesh manager		virtual coreRef< ITexture >		GetTexture() 	= 0;		// retrieves a texture from the texture manager		virtual coreRef< ITerrain >		GetTerrain() 	= 0;		// retrieves a terrain from the terrain manager};IGraphics* IGraphics::graphics = NULL;#endif // _CORE_GRAPHICS


core_ref.h:
#ifndef _CORE_REF#define _CORE_REFtemplate < typename T >class coreRef{	public:		/// Constructors and Destructors		~coreRef(){			if( ptr ){				ptr->count--;								if( ptr->count == 0 ){					// destroy the actual data					delete ptr->data;					ptr->data = NULL;										// there's no longer any need for ptr, so do housework					delete ptr;				}				// this class should not point to the reference anymore, don't want the user trying to access something they shouldn't				ptr = NULL;			}		}				coreRef( const coreRef< T >& ref ): ptr( ref.ptr ){			if( ptr != NULL && good() )				ptr->count++;		}				explicit coreRef( T* val = NULL ): ptr( NULL ){			if( val ){				ptr = new _counter;				ptr->data = val;				ptr->count++;			}		}				/// Overloaded operators		coreRef& operator = ( const coreRef<T> ref ){			if ( this != &ref ){				ptr = ref->ptr;			}		}				T* operator -> () const {			return *ptr->data;		}				static const coreRef< T > null;				/// For testing the validity of the pointer		bool good(){			return ( ptr->data != NULL ) ? true : false;		}	protected:				/// The counter struct keeps track of the numer of references		struct _counter{			size_t count;			T* data;		}* ptr;		};#endif // _CORE_REF


i_mesh.h:
#ifndef _I_MESH#define _I_MESHclass IMesh{    public:        IMesh();        ~IMesh();                    protected:            private:        };#endif // _I_MESH


i_texture.h:
#ifndef _I_TEXTURE#define _I_TEXTUREclass ITexture{	public:		ITexture();		~ITexture();					protected:			private:		};#endif // _I_TEXTURE


i_terrain.h:
#ifndef _I_TERRAIN#define _I_TERRAINclass ITerrain{	public:		ITerrain();		~ITerrain();					protected:			private:		};#endif // _I_TERRAIN


That is everything currently included in my project, literal CnP.
Your core_ref.h header doesn't include the static member variable definition. See the very first response in this thread, but remember to add const.

This topic is closed to new replies.

Advertisement