Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Checked static cast on a reference

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.

like image 456
Suma Avatar asked Nov 29 '10 20:11

Suma


2 Answers

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.

like image 125
MSN Avatar answered Sep 19 '22 13:09

MSN


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.

like image 32
WolfgangP Avatar answered Sep 20 '22 13:09

WolfgangP