To generalize the type universe of smart pointers, we distinguish three potentially distinct types in a smart pointer:
The storage type. This is the type of pointee_. By “default”—in regular smart pointers—it is a raw pointer.
The pointer type. This is the type returned by operator->. It can be different from the storage type if you want to return a proxy object instead of just a pointer. (You will find an example of using proxy objects later in this chapter.)
The reference type. This is the type returned by operator*.
It would be useful if SmartPtr supported this generalization in a flexible way. Thus, the three types mentioned here ought to be abstracted in a policy called Storage.
In conclusion, smart pointers can, and should, generalize their pointee type. To do this, SmartPtr abstracts three types in a Storage policy: the stored type, the pointer type, and the reference type. Not all types necessarily make sense for a given SmartPtr instantiation. Therefore, in rare cases (handles), a policy might disable access to operator-> or operator* or both.