NullValue helper for templates


#1

This is something that I’ve had to whip up for some of my templates, so I thought I’d share it. Partly because it might be useful to someone else, but also because someone may have a better way of doing it!

I’ve got a few templates for table/array structures which require the ability to check if an ‘ElementType’ value is ‘null’, without resorting to a virtual interface. I wanted to minimise the amount of effort needed to get it to work for any new types, so I figured I’d try some (rudimentary) template-fu on it.

This works nicely for me; it automatically interprets pointers and ReferenceCountedObjectPtr as nullptr, and defining a default null value for some new type just takes a simple macro. To use it, you just put a NullValue member in the template class, and you can compare against that; it will automatically have the default implemented null value for that type, but you can replace it if necessary for specific cases.

[code]///////////////////////////////////////////////////////////////////////////
// Template for defining a default assumed ‘null’ value for various types.
///////////////////////////////////////////////////////////////////////////

template< typename ValueType > struct DefaultNullValue
{
static inline const ValueType get () { return ValueType(); };
};

///////////////////////////////////////////////////////////////////////////
// Specialisation for pointer value types
///////////////////////////////////////////////////////////////////////////

template struct DefaultNullValue < ValueType * >
{
static inline ValueType* const get () { return nullptr; }
};

///////////////////////////////////////////////////////////////////////////
// Specialisation for reference counted pointer value types
///////////////////////////////////////////////////////////////////////////

template struct DefaultNullValue < ReferenceCountedObjectPtr< ValueType > >
{
static inline ValueType* const get () { return nullptr; }
};

///////////////////////////////////////////////////////////////////////////
// Macro to acquire the default null value for a given type
///////////////////////////////////////////////////////////////////////////

#define DEFAULT_NULL_VALUE(ValueType) DefaultNullValue< ValueType >::get();

///////////////////////////////////////////////////////////////////////////
// Helper macro to implement a default null value for a given type
///////////////////////////////////////////////////////////////////////////

#define DefaultNullValue_DeclareForType(ValueType,expression)
template<> struct DefaultNullValue< ValueType >
{
static inline const ValueType get () { return expression; };
};

///////////////////////////////////////////////////////////////////////////
// Some basic null value implementations
///////////////////////////////////////////////////////////////////////////

DefaultNullValue_DeclareForType (var, var());
DefaultNullValue_DeclareForType (int, -1);

///////////////////////////////////////////////////////////////////////////
// Class encapsulating a null value, to aid in template classes which
// require the ability to test an unknown template parameter type for null.
///////////////////////////////////////////////////////////////////////////

template
class NullValue
{
public:
typedef PARAMETER_TYPE(ValueType) ParameterType;

NullValue ()                                        { value = DEFAULT_NULL_VALUE(ValueType); }
NullValue (ParameterType& nullValue) : value(nullValue) {}
NullValue (const NullValue& other) : value(other.value) {}
NullValue& operator= (ParameterType newValue)       { value = newValue; return *this; }
NullValue& operator= (const NullValue& other)       { value = other.value; return *this; }
bool operator== (ParameterType other) const         { return value == other; }
bool operator!= (ParameterType other) const         { return value != other; }
operator ValueType ()                               { return value; }
operator const ValueType () const                   { return value; }
const ValueType get () const                        { return value; }
~NullValue () {}

private:
ValueType value;
};

///////////////////////////////////////////////////////////////////////////
[/code]

I’d happily welcome any suggestions for alternative approaches! I’m not super-versed on this sort of template abuse, so there may be some simple tricks I’m not aware of.