Подтвердить что ты не робот

Специализация шаблона С++, вызывающие методы для типов, которые могут быть указателями или ссылками однозначно

Резюме

Есть ли способ вызвать метод класса на шаблонном типе, который может быть указателем или ссылкой, не зная, какие и не получить ошибки компилятора/компоновщика?


Подробнее

У меня есть шаблонная реализация 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

Но они могут быть указателем ИЛИ ссылкой, поскольку все они получены из 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

4b9b3361

Ответ 1

Маленькие перегруженные функции могут использоваться для преобразования ссылки в указатель:

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, иначе будет выбрана вторая. Оба возвращают указатель, что означает независимо от того, что elem в вашем коде, выражение ptr(elem) всегда будет указателем, который вы можете использовать для вызова функций-членов, как показано выше.

Так как ptr(elem) является указателем, что означает, что проверка его на NULL будет хорошей идеей:

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

Надеюсь, что это поможет.