C++ template specialization, calling methods on types that could be pointers or references unambiguously
c++, pointers, reference, template-specialization, templates
Solution
Small overloaded functions can be used to turn reference into pointer:
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!
Now instead of doing this:
if(elem->Intersects(_bounds) == false) return false;
if(elem.Intersects(_bounds) == false) return false;
Do this:
if( ptr(elem)->Intersects(_bounds) == false) return false;
If `elem` is a reference, the first overload `ptr` will be selected, else the second will be selected. Both returns pointer, which means irrespective of what `elem` is in your code, the expression `ptr(elem)` will always be a pointer which you can use to invoke the member functions, as shown above.
Since `ptr(elem)` is pointer, which means checking it for `nullptr` be good idea:
if( ptr(elem) && (ptr(elem)->Intersects(_bounds) == false)) return false;
Problem
Summary Is there a way to call a class method on a templated type that could be a pointer or a reference without knowing which and not get compiler/linker errors? Details I have a templated QuadTree implementation that can take any of the following non-trivial user-defined types: ``` //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 ``` But they could be a pointer OR a reference as they are all derived from a2de::Shape. So the specializations are declared 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 ``` The problem I am having is the ability to call a class method when the indirection (or lack thereof) is unknown and due to the templates, both sets of code are generated: ``` 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; //... } ``` If I change the above line to use the . (dot) notation: ``` 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; //... } ``` If I remove the reference-based types in favor of the pointer-based types (including in the declaration and usage of the Quadtree class) I get the error `left of .<function-name> must have class/struct/union`. If I remove the pointer-based type in favor of the reference-based types (including in the declaration and usage of the Quadtree class) I get the aforementioned `reference to pointer is illegal` again. compiler: VS2010-SP1