Original Post
I''m in the process of writing some code which can represent any value by using a Value object, and can do casts between arbitrary values by using Cast objects (if they exist for two different types of values).
The whole thing is using pluggable factories to allow easy adding of more value types (for instance, classes) later on. The problem is that I''m getting linker errors.
I''m using VS.NET 2003 as my compiler - unmanaged C++.
First, some code (apologies for the horrid formatting in advance - i''m using 4 space tabs):
System.h
#pragma once
#include <string>
#include <map>
#include <vector>
#include <assert.h>
using namespace std;
namespace System {
typedef signed __int8 sint8;
typedef unsigned __int8 uint8;
typedef signed __int16 sint16;
typedef unsigned __int16 uint16;
typedef signed __int32 sint32;
typedef unsigned __int32 uint32;
typedef signed __int64 sint64;
typedef unsigned __int64 uint64;
typedef float real32;
typedef double real64;
typedef basic_string<uint8> binstring;
typedef uint32 idtype;
typedef uint16 hashtype;
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
namespace Utility {
class IRefCountable {
public:
virtual ~IRefCountable() {};
virtual void addRef() = 0;
virtual void subRef() = 0;
virtual sint32 getRefCount() = 0;
};
class SimpleRefCount : IRefCountable {
protected:
sint32 refCount;
public:
SimpleRefCount() : refCount(0) {};
virtual ~SimpleRefCount() {};
virtual void addRef() { refCount++; };
virtual void subRef() { refCount--; };
virtual sint32 getRefCount() { return refCount; };
};
class AutoDelete : public IRefCountable {
protected:
sint32 refCount;
public:
AutoDelete() : refCount(0) {};
virtual ~AutoDelete() {}; // FIXME: implement memory leak logging
virtual void addRef() { refCount++; };
virtual void subRef() { if ( --refCount < 1 ) delete this; };
virtual sint32 getRefCount() { return refCount; };
};
}
}
Value.h
#pragma once
#include "System.h"
namespace System {
class Value : public Utility::AutoDelete {
public:
class Type {
private:
static map< idtype, Type* > _types;
public:
static Type _VTsint8;
static Type _VTuint8;
static Type _VTsint16;
static Type _VTuint16;
static Type _VTsint32;
static Type _VTuint32;
static Type _VTsint64;
static Type _VTuint64;
static Type _VTreal32;
static Type _VTreal64;
private:
idtype id;
string name;
public:
Type( idtype type, string humanName ) : id( type ), name( humanName ) {
_types.insert( pair< idtype, Type* > ( type, this ) );
};
static Type* get( idtype type ) {
map< idtype, Type* >::iterator i = _types.find( type );
if ( i != _types.end() ) { return i->second; }
else { return NULL; }
};
static vector< Type* > getAll() {
vector< Type* > ret;
map< idtype, Type* >::iterator i = _types.begin();
while ( i++ != _types.end() ) { ret.push_back( i->second ); }
return ret;
};
};
class Factory {
private:
static map< Type*, Factory* > _factories;
protected:
virtual Value* manufacture() = 0;
public:
Factory( Value::Type* type ) {
_factories.insert( pair< Type*, Factory* > ( type, this ) );
};
static Value* create( Type* type ) {
map< Type*, Factory* >::iterator i = _factories.find( type );
if ( i != _factories.end() ) { return i->second->manufacture(); }
else { return NULL; }
};
};
class Cast {
private:
static map< pair< Type*, Type* >, Cast* > _casts;
protected:
virtual Value* performCast( Value* in ) = 0;
public:
Cast( Type* from, Type* to ) {
_casts.insert( pair< pair< Type*, Type* >, Cast* >
( pair< Type*, Type* > ( from, to ), this ) );
};
static Value* typecast( Value* v, Type* type ) {
assert( v ); assert( type );
map< pair< Type*, Type* >, Cast* >::iterator i
= _casts.find( pair< Type*, Type* > ( v->getType(), type ) );
if ( i != _casts.end() ) { return i->second->performCast( v ); }
else { return NULL; }
};
};
public:
virtual Type* getType() = 0;
virtual void set( Value* v ) = 0;
virtual Value* getCopy() = 0;
};
///////////////////////////////////////////////////////////////////////////////
template< class valueType, Value::Type* valueTypeID >
class simpleValue : public Value {
public:
class Factory : public Value::Factory {
private:
static const Factory __f;
protected:
virtual Value* manufacture() {
return new simpleValue< valueType, valueTypeID >;
};
public:
Factory() : Value::Factory( valueTypeID ) { };
};
private:
valueType value;
public:
simpleValue() { };
simpleValue( valueType& v ) : value(v) { };
virtual valueType get() { return value; };
virtual Value* getCopy() { return new simpleValue< valueType, valueTypeID >( value ); };
virtual void set( valueType& v ) { value = v; };
virtual void set( Value* v ) {
Value* casted = Value::Cast::typecast( v, valueTypeID );
if ( casted ) {
simpleValue< valueType, valueTypeID >* v2 =
(simpleValue< valueType, valueTypeID >*) casted;
value = v2->get();
delete casted, v2;
}
};
virtual Value::Type* getType() { return valueTypeID; };
};
///////////////////////////////////////////////////////////////////////////////
typedef simpleValue< sint8, &Value::Type::_VTsint8 > Vsint8;
typedef simpleValue< uint8, &Value::Type::_VTuint8 > Vuint8;
typedef simpleValue< sint16, &Value::Type::_VTsint16 > Vsint16;
typedef simpleValue< uint16, &Value::Type::_VTuint16 > Vuint16;
typedef simpleValue< sint32, &Value::Type::_VTsint32 > Vsint32;
typedef simpleValue< uint32, &Value::Type::_VTuint32 > Vuint32;
typedef simpleValue< sint64, &Value::Type::_VTsint64 > Vsint64;
typedef simpleValue< uint64, &Value::Type::_VTuint64 > Vuint64;
typedef simpleValue< real32, &Value::Type::_VTreal32 > Vreal32;
typedef simpleValue< real64, &Value::Type::_VTreal64 > Vreal64;
}
Value.cpp #include "Value.h" using namespace System; // all this stuff is here for implementing serialisation later Value::Type Value::Type::_VTsint8 = Value::Type( ''SI8_'', "integer - signed 8-bit" ); Value::Type Value::Type::_VTuint8 = Value::Type( ''UI8_'', "integer - unsigned 8-bit" ); Value::Type Value::Type::_VTsint16 = Value::Type( ''SI16'', "integer - signed 16-bit" ); Value::Type Value::Type::_VTuint16 = Value::Type( ''UI16'', "integer - unsigned 16-bit" ); Value::Type Value::Type::_VTsint32 = Value::Type( ''SI32'', "integer - signed 32-bit" ); Value::Type Value::Type::_VTuint32 = Value::Type( ''UI32'', "integer - unsigned 32-bit" ); Value::Type Value::Type::_VTsint64 = Value::Type( ''SI64'', "integer - signed 64-bit" ); Value::Type Value::Type::_VTuint64 = Value::Type( ''UI64'', "integer - unsigned 64-bit" ); Value::Type Value::Type::_VTreal32 = Value::Type( ''FP32'', "real - 32-bit" ); Value::Type Value::Type::_VTreal64 = Value::Type( ''FP64'', "real - 64-bit" );The problem is when trying to use any of this code, I get linker errors. Specifically, adding this to main():
System::Vuint32 v;If I don''t include that code, I don''t get the linker errors. Now, I''ve figured that it has to be something to do with my static member initialisation. I''ve come to the conclusion that adding this code to initialise the maps in the Cast and Type classes to Value.cpp removes the linking errors:
map< pair< Value::Type*, Value::Type* >, Value::Cast* > Value::Cast::_casts; map< idtype, Value::Type* > Value::Type::_types;Great, no errors. But that means that something is wrong with my factory code - the static members for Type and Cast aren''t initialising on their own. Which they should be - they''re pretty much clones of the Factory class (taken from the Pluggable Factories article on this site), which works fine and doesn''t give me problems. I know I have to be missing something obvious - ideas anyone? - Nanoprobe