Try adding a static_cast to the template definition.Nope, that doesn't work either. Thinking about C++ templates...
Final answer:
I'm stumped as to why your method doesn't work, but with some further thought I think it's also not the most correct way to do it. With your method, if you have a handle type where 0
isn't the correct null value, you would need to specify the appropriate null value
every time you instantiate a handle of that type.
My solution: template specialization. Observe. (And please pardon the reformatting. I find it easier to think in my own coding style.)
// This templated function handles creating appropriate null values for
// handles. Obviously. The default action is to assume that 0 makes an
// appropriate null.
template< class NativeHandle >
NativeHandle NullHandleFactory()
{
return 0;
}
// Here is your handle class, pretty much unchanged except that we now
// call NullHandleFactory everywhere.
template< class NativeHandle >
class Handle
{
public:
typedef NativeHandle Type;
Handle(NativeHandle h = NullHandleFactory< NativeHandle >())
: _native (h)
{
}
bool IsNull() const throw()
{
return _native == NullHandleFactory< NativeHandle >();
}
NativeHandle ToNative() const { return _native; }
void Reset (NativeHandle h = NullHandleFactory< NativeHandle >())
{
_native = h;
}
bool operator == (Handle h) const
{
return _native == h.ToNative();
}
bool operator != (Handle h) const
{
return _native != h.ToNative ();
}
static NativeHandle NullValue() throw()
{
return NullHandleFactory< NativeHandle >();
}
protected:
NativeHandle H() const { return _native; }
NativeHandle& BaseHRef() { return _native; }
protected:
NativeHandle _native;
};
// Here is your regular old HINSTANCE handle. The unspecialized
// NullHandleFactory is appropriate here, since HINSTANCE's are pointers
// and 0 is a good pointer value.
class Instance: public Handle< HINSTANCE >
{
public:
Instance(HINSTANCE h = 0)
: Handle< HINSTANCE >(h)
{
}
};
// But here's a type that is NOT implicitly convertible from 0.
struct NoZerosAllowed
{
};
// So what do we do? We specialize the NullHandleFactory template function
// for this specific type to return something appropriate.
template<>
NoZerosAllowed NullHandleFactory()
{
return NoZerosAllowed();
}
// Now our FunkyHandle class can treat NoZerosAllowed handles just like
// other handles
class FunkyHandle : public Handle< NoZerosAllowed >
{
public:
// If we hadn't specialized NullHandleFactory, an error would be thrown here
// because we're using Handle's default constructor, which calls
// NullHandleFactory
FunkyHandle()
{
}
};