Long ago I have created a following template so that I get an assert whenever I perform a static_cast but the type is not what I assume it to be:
/// perform a static_cast asserted by a dynamic_cast
template <class Type, class SourceType>
Type static_cast_checked(SourceType item)
{
Assert(!item || dynamic_cast<Type>(item));
return static_cast<Type>(item);
}
Today I wanted to create a variant which would work not only with pointers, but with references as well:
/// overload for reference
template <class Type, class SourceType>
Type &static_cast_checked(SourceType &item)
{
Assert(dynamic_cast<Type *>(&item));
return static_cast<Type>(item);
}
However, the compiler does not seem to use this overload when I am casting a reference to another reference. I am afraid I do not understand template resolution rules enough to understand why, or to be able to create a variant which works.
Note: I cannot catch the bad_cast exception
instead of checking dynamic_cast<Type *>
for NULL, as exceptions are disabled for this project.
Remove *
and &
from the return types:
/// perform a static_cast asserted by a dynamic_cast
template <class Type, class SourceType>
Type static_cast_checked(SourceType *item)
{
Assert(!item || dynamic_cast<Type>(item));
return static_cast<Type>(item);
}
template <class Type> struct make_pointer
{
typedef Type *PointerType;
};
template <class Type> struct make_pointer<Type &>
{
typedef Type *PointerType;
};
/// overload for reference
template <class Type, class SourceType>
Type static_cast_checked(SourceType &item)
{
Assert(dynamic_cast<typename make_pointer<Type>::PointerType>(&item));
return static_cast<Type>(item);
}
Then you can use your desired syntax:
Derived *d= static_cast_checked<Derived *>(b);
Derived &d= static_cast_checked<Derived &>(b);
EDIT: added a pointer type conversion.
This works:
/// perform a static_cast asserted by a dynamic_cast
template <class Type, class SourceType>
Type* static_cast_checked(SourceType *item)
{
Assert(!item || dynamic_cast<Type*>(item));
return static_cast<Type*>(item);
}
/// overload for reference
template <class Type, class SourceType>
Type &static_cast_checked(SourceType &item)
{
Assert(dynamic_cast<Type *>(&item));
return static_cast<Type&>(item);
}
Use it like this:
Dervied d;
Base* pbase = static_cast_checked<Base>(&d);
Base& rbase = static_cast_checked<Base>(d);
This solution relies on overloading function templates. Your solution didn't work because your first template is too general, it already includes your second function. Note that there is no specialization for function templates! You can only specialize class templates.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With