web-dev-qa-db-ja.com

C ++テンプレートの特殊化、ポインターまたは参照である可能性のある型のメソッドを明確に呼び出す

概要

コンパイラー/リンカーエラーを取得せずに、ポインターまたは参照であるテンプレート化された型でクラスメソッドを呼び出す方法はありますか?


詳細

次の重要なユーザー定義型のいずれかを取ることができるテンプレート化されたQuadTree実装があります。

//Abstract Base Class
a2de::Shape

//Derived Classes
a2de::Point
a2de::Line
a2de::Rectangle
a2de::Circle
a2de::Ellipse
a2de::Triangle
a2de::Arc
a2de::Spline
a2de::Sector
a2de::Polygon

しかし、これらはポインタである可能性がありますOR参照はすべてa2de :: Shapeから派生しているため、特殊化は次のように宣言されます。

template class QuadTree<a2de::Shape&>;
//...similar for all derived types as references.

template class QuadTree<a2de::Shape*>;
//...similar for all derived types as pointers

私が抱えている問題は、間接指定(またはその欠如)が不明で、テンプレートが原因で両方のコードセットが生成されたときにクラスメソッドを呼び出す機能です。

template<typename T>
bool QuadTree<T>::Add(T& elem) {

    //When elem of type T is expecting a pointer here
    //-> notation fails to compile where T is a reference i.e.:
    //template class QuadTree<a2de::Shape&>
    //with "pointer to reference is illegal"

    if(elem->Intersects(_bounds) == false) return false;

    //...
}

上記の行を変更して、 (ドット)表記:

template<typename T>
bool QuadTree<T>::Add(T& elem) {

    //When elem of type T is expecting a reference here
    //. (dot) notation fails to compile where T is a pointer i.e.:
    //template class QuadTree<a2de::Shape*>
    //with "pointer to reference is illegal"

    if(elem.Intersects(_bounds) == false) return false;

    //...

}

ポインタベースのタイプを優先して参照ベースのタイプを削除すると(Quadtreeクラスの宣言と使用法を含む)、エラーleft of .<function-name> must have class/struct/union

参照ベースのタイプを優先してポインタベースのタイプを削除すると(Quadtreeクラスの宣言と使用法を含む)、前述のreference to pointer is illegal再び。

コンパイラ:VS2010-SP1

30
Casey

小さなオーバーロードされた関数を使用してreferencepointerに変換できます。

_template<typename T>
T * ptr(T & obj) { return &obj; } //turn reference into pointer!

template<typename T>
T * ptr(T * obj) { return obj; } //obj is already pointer, return it!
_

これを行う代わりに:

_ if(elem->Intersects(_bounds) == false) return false;
 if(elem.Intersects(_bounds) == false) return false;
_

これを行う:

_ if( ptr(elem)->Intersects(_bounds) == false) return false;
_

elemが参照の場合、最初のオーバーロードptrが選択され、それ以外の場合は2番目のオーバーロードが選択されます。どちらもpointerを返します。つまり、コード内のelemが何であるかに関係なく、式ptr(elem)は常にpointerになります。上記のように、を使用してメンバー関数を呼び出すことができます。

ptr(elem)はポインターであるため、NULLをチェックすることをお勧めします。

_ if( ptr(elem) && (ptr(elem)->Intersects(_bounds) == false)) return false;
_

お役に立てば幸いです。

43
Nawaz