Sign in to follow this  
webwraith

static const templates

Recommended Posts

webwraith    239
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]

Share this post


Link to post
Share on other sites
SiCrane    11839
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.

Share this post


Link to post
Share on other sites
Makaan    100
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.

Share this post


Link to post
Share on other sites
webwraith    239
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.

Share this post


Link to post
Share on other sites
SiCrane    11839
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.

Share this post


Link to post
Share on other sites
webwraith    239
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.

Share this post


Link to post
Share on other sites
SiCrane    11839
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.

Share this post


Link to post
Share on other sites
webwraith    239
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_REF

template < 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_MESH

class IMesh
{
public:
IMesh();
~IMesh();


protected:

private:

};


#endif // _I_MESH



i_texture.h:

#ifndef _I_TEXTURE
#define _I_TEXTURE

class ITexture
{
public:
ITexture();
~ITexture();


protected:

private:

};


#endif // _I_TEXTURE



i_terrain.h:

#ifndef _I_TERRAIN
#define _I_TERRAIN

class ITerrain
{
public:
ITerrain();
~ITerrain();


protected:

private:

};


#endif // _I_TERRAIN



That is everything currently included in my project, literal CnP.

Share this post


Link to post
Share on other sites
SiCrane    11839
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.

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