Especialización en plantillas de C++, llamando a métodos en tipos que podrían ser punteros o referencias inequívocamente


Resumen

¿Hay alguna manera de llamar a un método de clase en un tipo templado que podría ser un puntero o una referencia sin saber cuál y no obtener errores de compilador/enlazador?


Detalles

Tengo una implementación de QuadTree templada que puede tomar cualquiera de los siguientes tipos no triviales definidos por el usuario:

//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

Pero podrían ser un puntero O una referencia, ya que todos se derivan de a2de::Shape. Así se declaran las especializaciones as:

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

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

El problema que tengo es la capacidad de llamar a un método de clase cuando la indirección (o falta de ella) es desconocida y debido a las plantillas, se generan ambos conjuntos de código:

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;

    //...
}

Si cambio la línea anterior para usar el . notación (punto):

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;

    //...

}

Si elimino los tipos basados en referencia en favor de los tipos basados en puntero (incluso en la declaración y el uso de la clase Quadtree) obtengo el error left of .<function-name> must have class/struct/union.

Si elimino el tipo basado en puntero en favor de los tipos basados en referencia (incluso en la declaración y el uso de la clase Quadtree) obtengo el reference to pointer is illegal antes mencionado de nuevo.

Compilador: VS2010-SP1

Author: Casey, 2013-01-22

1 answers

Se pueden usar pequeñas funciones sobrecargadas para convertir referencia en puntero :

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!

Ahora en lugar de hacer esto:

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

Haz esto:

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

Si elem es una referencia, se seleccionará la primera sobrecarga ptr, de lo contrario se seleccionará la segunda. Both returns pointer , lo que significa que independientemente de lo que elem esté en su código, la expresión ptr(elem) siempre será un pointer que puede usar para invocar las funciones miembro, como se muestra arriba.

Dado que ptr(elem) es puntero, lo que significa que comprobarlo para NULL es una buena idea:

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

Espero que eso ayude.

 39
Author: Nawaz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-22 19:56:18