2010-11-29 7 views
5

昔、私は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); 
} 

しかし、コンパイラは、私は別の参照への参照をキャストしていたときに、このオーバーロードを使用していないようです:だけでなく、ポインタではなく、参照していないだけで動作しますバリアントを作成します。私は、理由を理解するのに十分なテンプレート解決規則を理解していないか、または動作するバリアントを作成できるようにするのは怖いです。

注:このプロジェクトでは例外が無効になっているため、dynamic_cast<Type *>にNULLを設定する代わりにbad_cast exceptionをキャッチすることはできません。

+1

あなたは 'のSourceTypeの*'のための過負荷を追加して、オリジナルのものを引退することができますか?あなたは値の型をまったくサポートする必要がありますか? (そして、それは問題を解決します、私は今疑問に思っていますか?) –

+1

私はこれらのコード行について考えました。なぜそれが必要なのか理解できません。動的キャストを使用して静的キャストをチェックすると、オブジェクトのみをチェックできるだけでなく、静的キャストはダイナミックキャスト可能です。それは 'dynamic_cast'の再実装です。動的キャストと静的キャストの違いは、動的キャストがvtableと静的キャストを調べていないことです。 – nutario

+0

これは静的なキャストですが、キャストしているタイプについての仮定が間違っていることをデバッグ時間として通知します。 – Suma

答えて

5

削除*&は:

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

EDIT:

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

は、次に、あなたの希望の構文を使用することができますポインタ型変換を追加しました。

+1

gccを使用している場合は、少なくとも、参照( 'Assert(dynamic_cast (&item));)からポインタ型を取得できません - 他のコンパイラについてはわかりません。 – nutario

+0

@nutario、ああ、あなたは正しいです。 – MSN

+0

@nutario、fixed! – MSN

0

は、以下を試してください

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

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

そしてすべてのポインタは、第一の変形例を使用すると、すべての参照が(IIRC)部分特殊規則の第2を使用します。

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番目の関数が含まれているため、あなたのソリューションは機能しませんでした。関数テンプレートの特殊化はないことに注意してください。クラステンプレートは特殊化することしかできません。戻り値の型から

+0

偉大な、これは簡単で、それは非常にうまく動作します。可能であれば、私はまだstatic_cast_checked またはstatic_cast_checked と書くことができる解決策を好むでしょう。誰かがいくつか作成できますか?私は今、特別なテンプレートクラスを使用して努力しています。 – Suma

+0

私は様々な試み(型特質やクラス特殊化を含む)を試してみましたが、コンパイルの解決には至りませんでした。 – WolfgangA

+0

私は、オーバーロードとクラススペシャライゼーションを組み合わせたソリューションを見つけたと思います。あなたは私の新しい答えをチェックして、OKかどうか確認できますか? – Suma

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_castまたはdynamic_castのように動作します: ``

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

ニース。それは私のソリューションとほぼ同じで、テクニカルバックグラウンドは同じですが、ブーストを使用すると少し短くなります。 – Suma

関連する問題