Update: In C ++ 11 kann man std::addressof
anstelle von verwenden boost::addressof
.
Kopieren wir zuerst den Code von Boost, abzüglich der Compiler-Umgehung von Bits:
template<class T>
struct addr_impl_ref
{
T & v_;
inline addr_impl_ref( T & v ): v_( v ) {}
inline operator T& () const { return v_; }
private:
addr_impl_ref & operator=(const addr_impl_ref &);
};
template<class T>
struct addressof_impl
{
static inline T * f( T & v, long ) {
return reinterpret_cast<T*>(
&const_cast<char&>(reinterpret_cast<const volatile char &>(v)));
}
static inline T * f( T * v, int ) { return v; }
};
template<class T>
T * addressof( T & v ) {
return addressof_impl<T>::f( addr_impl_ref<T>( v ), 0 );
}
Was passiert, wenn wir einen Verweis auf die Funktion übergeben ?
Hinweis: addressof
Kann nicht mit einem Zeiger auf die Funktion verwendet werden
Wenn in C ++ void func();
deklariert ist, func
ist dies ein Verweis auf eine Funktion, die kein Argument akzeptiert und kein Ergebnis zurückgibt. Dieser Verweis auf eine Funktion kann trivial in einen Zeiger auf eine Funktion umgewandelt werden - von @Konstantin
: Nach 13.3.3.2 sind beide T &
und T *
für Funktionen nicht zu unterscheiden. Die erste ist eine Identitätskonvertierung und die zweite ist eine Funktion-zu-Zeiger-Konvertierung, die beide den Rang "Exakte Übereinstimmung" haben (13.3.3.1.1, Tabelle 9).
Der Verweis auf die Funktion geht durch addr_impl_ref
, es gibt eine Mehrdeutigkeit in der Überlastungsauflösung für die Auswahl von f
, die dank des Dummy-Arguments gelöst wird, das eine Premiere 0
ist int
und zu einer long
(Integral Conversion) befördert werden könnte.
Wir geben also einfach den Zeiger zurück.
Was passiert, wenn wir einen Typ mit einem Konvertierungsoperator übergeben?
Wenn der Konvertierungsoperator a ergibt T*
, haben wir eine Mehrdeutigkeit: Für f(T&,long)
das zweite Argument ist eine integrale Promotion erforderlich, während für f(T*,int)
den Konvertierungsoperator das erste aufgerufen wird (danke an @litb).
Das ist , wenn addr_impl_ref
Tritten an. Die C ++ Standard - Aufträge , daß eine Konvertierungssequenz höchstens einen benutzerdefinierten Umwandlung enthalten. Indem addr_impl_ref
wir den Typ einschließen und die Verwendung einer Konvertierungssequenz bereits erzwingen, "deaktivieren" wir jeden Konvertierungsoperator, mit dem der Typ geliefert wird.
Somit wird die f(T&,long)
Überlastung ausgewählt (und die integrale Förderung durchgeführt).
Was passiert bei einem anderen Typ?
Somit wird die f(T&,long)
Überladung ausgewählt, da dort der Typ nicht mit dem T*
Parameter übereinstimmt .
Hinweis: Aus den Anmerkungen in der Datei zur Borland-Kompatibilität geht hervor, dass Arrays nicht in Zeiger zerfallen, sondern als Referenz übergeben werden.
Was passiert bei dieser Überlastung?
Wir möchten vermeiden operator&
, dass der Typ angewendet wird, da er möglicherweise überladen ist.
Der Standard garantiert, dass reinterpret_cast
für diese Arbeit verwendet werden kann (siehe Antwort von @Matteo Italia: 5.2.10 / 10).
Boost fügt einige Feinheiten mit const
und volatile
Qualifikationsmerkmalen hinzu, um Compiler-Warnungen zu vermeiden (und verwendet a ordnungsgemäß const_cast
, um sie zu entfernen).
- Besetzung
T&
zuchar const volatile&
- Zieh das
const
und ausvolatile
- Wenden Sie den
&
Operator an, um die Adresse zu übernehmen
- Wirf zurück zu a
T*
Das const
/ volatile
Jonglieren ist ein bisschen schwarze Magie, aber es vereinfacht die Arbeit (anstatt 4 Überladungen bereitzustellen). Beachten Sie, dass, da T
unqualifiziert ist, wenn wir a bestehen ghost const&
, dies der Fall T*
ist ghost const*
, die Qualifikanten nicht wirklich verloren gegangen sind.
BEARBEITEN: Die Zeigerüberladung wird für den Zeiger auf Funktionen verwendet, ich habe die obige Erklärung etwas geändert. Ich verstehe immer noch nicht, warum es notwendig ist .
Die folgende Ideone-Ausgabe fasst dies etwas zusammen.