Aggiornamento: in C ++ 11, si può usare al std::addressof
posto di boost::addressof
.
Copiamo prima il codice da Boost, meno che il compilatore funzioni attorno ai bit:
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 );
}
Cosa succede se passiamo un riferimento alla funzione ?
Nota: addressof
non può essere utilizzato con un puntatore per funzionare
In C ++ se void func();
è dichiarato, allora func
è un riferimento a una funzione che non accetta alcun argomento e non restituisce alcun risultato. Questo riferimento a una funzione può essere banalmente convertito in un puntatore a funzione - da @Konstantin
: secondo 13.3.3.2 entrambi T &
e T *
sono indistinguibili per le funzioni. Il primo è una conversione di identità e il secondo è una conversione da funzione a puntatore entrambi con rango "Corrispondenza esatta" (13.3.3.1.1 tabella 9).
Il riferimento alla funzione passa attraverso addr_impl_ref
, c'è un'ambiguità nella risoluzione del sovraccarico per la scelta di f
, che è risolta grazie all'argomento fittizio 0
, che è il int
primo e potrebbe essere promosso a long
(Conversione integrale).
Quindi restituiamo semplicemente il puntatore.
Cosa succede se passiamo un tipo con un operatore di conversione?
Se l'operatore di conversione produce a T*
allora abbiamo un'ambiguità: per f(T&,long)
una promozione integrale è necessaria per il secondo argomento mentre per f(T*,int)
l'operatore di conversione viene chiamato il primo (grazie a @litb)
Ecco quando addr_impl_ref
entra in gioco. Lo standard C ++ impone che una sequenza di conversione possa contenere al massimo una conversione definita dall'utente. Inserendo il tipo addr_impl_ref
e forzando già l'uso di una sequenza di conversione, "disabilitiamo" qualsiasi operatore di conversione fornito dal tipo.
In tal modo f(T&,long)
viene selezionato il sovraccarico (e viene eseguita la promozione integrale).
Cosa succede per qualsiasi altro tipo?
Quindi f(T&,long)
viene selezionato il sovraccarico, perché lì il tipo non corrisponde al T*
parametro.
Nota: dalle osservazioni nel file relative alla compatibilità di Borland, le matrici non si deteriorano in puntatori, ma vengono passate per riferimento.
Cosa succede in questo sovraccarico?
Vogliamo evitare di applicare operator&
al tipo, poiché potrebbe essere stato sovraccarico.
Lo standard garantisce che reinterpret_cast
può essere utilizzato per questo lavoro (vedi la risposta di @Matteo Italia: 5.2.10 / 10).
Boost aggiunge alcuni aspetti positivi const
e volatile
qualificatori per evitare gli avvisi del compilatore (e utilizzare correttamente a const_cast
per rimuoverli).
- Cast
T&
tochar const volatile&
- Striscia
const
evolatile
- Applicare l'
&
operatore per prendere l'indirizzo
- Torna a a
T*
Il const
/ volatile
giocoleria è un po 'di magia nera, ma semplifica il lavoro (piuttosto che fornire 4 sovraccarichi). Si noti che poiché T
non è qualificato, se si passa a ghost const&
, allora lo T*
è ghost const*
, quindi le qualificazioni non sono state realmente perse.
EDIT: il sovraccarico del puntatore viene utilizzato per il puntatore alle funzioni, ho modificato in qualche modo la spiegazione sopra. Non capisco ancora perché sia necessario .
Il seguente output di ideone lo riassume in qualche modo.