I must be missing something. In “normal C++”, how would you expect the = operator in the ReferenceCountedObjectPtr template class to look like?
In glancing at the classes, ReferenceCountedObject appears to be the ability to keep a reference count. So classes can inherent this ability by inheriting from this class.
In the early days of C++, lots of us did this with things like ‘list’ classes, the functionality to be part of a linked list, etc. And what we ran into was that we had to do oodles of casting to put the inherited functionality to work. All that casting defeats the purpose of a tightly cast language, so we would do things like make a special usage class for each type of object to encapsulate the casting. In other words, you would inherit ListObject, but then there would be a wrapper class for usage, AList, BList, etc. all derived from the List class (class that knew how to manipulate ListObject objects).
If RefereceCountedObjectPtr was not a template, but just a * to ReferenceCountedObject that did the basic work of incrementing/decrementing references, you would have the same type of situation. Every time you wanted to use the Ptr, you would have to cast it to your descendant object. All that casting would be a pain, so you would make a wrapper class to do it for you. That is, you wouldn’t just inherent ReferenceCountedObject, you would make your own pointer class that inherited from ReferenceCountedObjectPtr as well…
Enter Templates. Write the usage class once, and specific the target descendant at instantiation. Instead of creating a new SomethingList class every time I wanted to use the inherited functionality from ListObject, I could just go List, List. The template is automating all the casting in a robust way, so I don’t have to do it myself, over and over. In the first template experiments, it literally was translated into C style casting.
Think of ReferenceCountedObjectPtr as a non template, and look at your desired syntax if we think of templates as casting:
ReferenceCountedObjectPtr ptr1;
ReferenceCountedObjectPtr ptr2;
(A *)ptr1 = (B *)ptr2;
I’m expressly casting, so I’m telling the compiler exactly how to treat each object ptr. Templates exist primarily to automatically cast base object usage functionality to a specific descendant. This is a reference to a countable object of type A, this is a reference to a countable object of type B…
In that sense, the syntax that works makes perfect sense to me. 'I want to keep to references to this object, one expressly cast to the class it is, one expressly cast to a base class. The object is passed to both references (getObject). Creating a different type of reference directly from the first one just looks wrong to me. But, again, I could be missing something.