Consider the following program:
struct ghost
{
// ghosts like to pretend that they don\'t exist
ghost* operator&() const volatile { return 0; }
}
The trick behind boost::addressof and the implementation provided by @Luc Danton relies on the magic of the reinterpret_cast; the standard explicitly states at §5.2.10 ¶10 that
An lvalue expression of type
T1can be cast to the type “reference toT2” if an expression of type “pointer toT1” can be explicitly converted to the type “pointer toT2” using areinterpret_cast. That is, a reference castreinterpret_casthas the same effect as the conversion(x) *reinterpret_castwith the built-in(&x) &and*operators. The result is an lvalue that refers to the same object as the source lvalue, but with a different type.
Now, this allows us to convert an arbitrary object reference to a char & (with a cv qualification if the reference is cv-qualified), because any pointer can be converted to a (possibly cv-qualified) char *. Now that we have a char &, the operator overloading on the object is no longer relevant, and we can obtain the address with the builtin & operator.
The boost implementation adds a few steps to work with cv-qualified objects: the first reinterpret_cast is done to const volatile char &, otherwise a plain char & cast wouldn't work for const and/or volatile references (reinterpret_cast cannot remove const). Then the const and volatile is removed with const_cast, the address is taken with &, and a final reinterpet_cast to the "correct" type is done.
The const_cast is needed to remove the const/volatile that could have been added to non-const/volatile references, but it does not "harm" what was a const/volatile reference in first place, because the final reinterpret_cast will re-add the cv-qualification if it was there in first place (reinterpret_cast cannot remove the const but can add it).
As for the rest of the code in addressof.hpp, it seems that most of it is for workarounds. The static inline T * f( T * v, int ) seems to be needed only for the Borland compiler, but its presence introduces the need for addr_impl_ref, otherwise pointer types would be caught by this second overload.
Edit: the various overloads have a different function, see @Matthieu M. excellent answer.
Well, I'm no longer sure of this either; I should further investigate that code, but now I'm cooking dinner :) , I'll have a look at it later.