检查参考上的静态强制转换

时间:2010-11-29 20:06:14

标签: c++ templates casting

很久以前我已经创建了一个以下模板,这样每当我执行static_cast时我都会得到一个断言但类型不是我认为的类型:

/// 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);
}

但是,当我转换对另一个引用的引用时,编译器似乎没有使用此重载。我恐怕我不明白模板解析规则足以理解为什么,或者能够创建一个有效的变体。

注意:我无法捕获bad_cast exception而不是检查dynamic_cast<Type *>是否为NULL,因为此项目禁用了异常。

4 个答案:

答案 0 :(得分:5)

从返回类型中删除*&

/// 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); 
} 

然后您可以使用所需的语法:

Derived *d= static_cast_checked<Derived *>(b);
Derived &d= static_cast_checked<Derived &>(b);

编辑:添加了指针类型转换。

答案 1 :(得分:2)

这有效:

/// 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);
}

像这样使用:

Dervied d;
Base* pbase = static_cast_checked<Base>(&d);
Base& rbase = static_cast_checked<Base>(d);

此解决方案依赖于重载功能模板。您的解决方案无效,因为您的第一个模板过于笼统,它已包含您的第二个功能。请注意,功能模板没有专业化!您只能专门化类模板。

答案 2 :(得分:1)

#include <boost/type_traits/add_pointer.hpp>

template <class Type, class SourceType>
Type static_cast_checked(SourceType *item)
{
  assert(!item || dynamic_cast<Type>(item));
  return static_cast<Type>(item);
}

template <typename Type,  class SourceType>
Type static_cast_checked(SourceType &item)
{
   typedef typename boost::add_pointer<Type>::type TypePtr;
   assert(dynamic_cast< TypePtr >(&item));
   return static_cast<Type>(item);
}

此实现类似于std-lib中的static_castdynamic_cast:``

    Base &b    = static_cast_checked<Base&>( a);
    Base* bPtr = static_cast_checked<Base*>(&a);

答案 3 :(得分:0)

尝试以下方法:

template<class Type, class SourceType>
Type* static_cast_checked(SourceType* item)
{
    // ... 
}

template<class Type, class SourceType>
Type& static_cast_checked(SourceType& item)
{
    // ... 
}

然后每个指针都将使用第一个变量,每个引用将使用部分特化规则(IIRC)中的第二个。