Laissez-nous d'abord copier le code de Boost, moins le compilateur de travail autour de 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 );
}
Ce qui se passe si on passe une référence à la fonction ?
Remarque: addressof
ne peut pas être utilisé avec un pointeur de fonction
En C++, si void func();
est déclarée, alors func
est une référence à une fonction ne prenant aucun argument et renvoie aucun résultat. Cette référence à une fonction peut être trivialement converti en un pointeur de fonction-d' @Konstantin
: Selon 13.3.3.2 les deux T &
et T *
sont indiscernables pour les fonctions. Le 1er est une Identité de conversion et le 2ème est la Fonction de Pointeur de la conversion à la fois d'avoir des "Correspondance Exacte" rang (13.3.3.1.1 tableau 9).
La référence à la fonction pass through addr_impl_ref
, il y a une ambiguïté dans la résolution de surcharge pour le choix de l' f
, ce qui est résolu grâce à l'argument factice 0
, ce qui est un int
première et pourrait être promu à un long
(Promotion Intégrale).
Ainsi, nous renvoie simplement le pointeur.
Qu'advient-il si l'on fait passer d'un type avec un opérateur de conversion ?
Si l'opérateur de conversion donne un T*
puis nous avons une ambiguïté: pour f(T&,long)
d'une Promotion Intégrale est nécessaire pour le deuxième argument, tandis que pour l' f(T*,int)
l'opérateur de conversion est appelée sur la première (merci à @litb)
C'est lors de l' addr_impl_ref
coups de pied dans. La Norme C++ mandats qu'une conversion de la séquence peut contenir au plus une conversion définie par l'utilisateur. En enveloppant le type en addr_impl_ref
et de forcer l'utilisation d'une conversion d'une séquence déjà, nous "désactiver" tout opérateur de conversion que le type qui vient avec.
Ainsi, l' f(T&,long)
de surcharge est activée (et à la Promotion Intégrale réalisée).
Ce qui se passe pour tout autre type ?
Ainsi, l' f(T&,long)
de surcharge est activée, parce que là, le type ne correspond pas à l' T*
paramètre.
Note: le commentaire dans le fichier concernant Borland compatibilité, les tableaux ne baissent pas pour les pointeurs, mais sont passés par référence.
Ce qui se passe dans cette surcharge ?
Nous voulons éviter d'appliquer des operator&
pour le type, comme il a pu être surchargé.
La Norme garantit reinterpret_cast
peut être utilisé pour ce travail (voir @Matteo Italia réponse: 5.2.10/10).
Boost ajoute quelques subtilités avec const
et volatile
qualificatifs pour éviter les avertissements du compilateur (et utiliser correctement un const_cast
pour les supprimer).
- Cast
T&
de char const volatile&
- Stip l'
const
et volatile
- Appliquer l'
&
de l'opérateur de prendre l'adresse
- Cast retour à un
T*
L' const
/volatile
jonglerie est un peu de la magie noire, mais il ne simplifient le travail (plutôt que de fournir des 4 surcharges). A noter que depuis T
non qualifié est, si l'on fait passer un ghost const&
, alors T*
est ghost const*
, donc les qualificatifs n'ont pas vraiment été perdu.
EDIT: le pointeur de la surcharge est utilisé pour le pointeur de fonctions, j'ai modifié l'explication ci-dessus un peu. Je ne comprends toujours pas pourquoi il est nécessaire de bien.
La suite ideone sortie résume bien la situation, un peu.