Güncelleme: C ++ 11'de std::addressofbunun yerine kullanılabilir boost::addressof.
Önce kodu Boost'tan kopyalayalım, derleyici bitler etrafında çalışır:
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 );
}
İşleve referans gönderirsek ne olur ?
Not: addressofişlev göstermek için bir işaretçi ile kullanılamaz
C ++ ' void func();da bildirilirse, funcargüman almayan ve sonuç döndürmeyen bir işleve başvuru olur. Bir fonksiyona yapılan bu referans önemsiz bir şekilde fonksiyona bir göstergeye dönüştürülebilir - şuradan @Konstantin: 13.3.3.2'ye göre her ikisi de T &ve T *fonksiyonlar için ayırt edilemez. Birincisi bir Kimlik dönüşümüdür ve ikincisi de "Tam Eşleşme" derecesine sahip İşlevden İşaretçiye dönüşümdür (13.3.3.1.1 tablo 9).
İşlevine başvurunun geçmesine addr_impl_refseçimi için aşırı çözünürlükte bir belirsizlik vardır, fyapay değişken sayesinde çözülmektedir, 0bir olduğu, intbirinci ve bir terfi edilebilir long(İntegral Dönüştürme).
Böylece sadece işaretçiyi döndürüyoruz.
Bir dönüştürme operatörü ile bir tür geçirirsek ne olur?
Dönüştürme operatörü bir sonuç verirseT* , bir belirsizliğe sahibiz: f(T&,long)ikinci argüman için bir İntegral Tanıtım için gereklidir f(T*,int), dönüşüm operatörü için ise ilk çağrılır (@litb sayesinde)
O zaman addr_impl_ref. C ++ Standart görev devreye girer dönüşüm sekansı en fazla bir kullanıcı tanımlı dönüşümde içerebilir. Türü sararak ve addr_impl_refzaten bir dönüşüm sekansının kullanımını zorlayarak, türle birlikte gelen herhangi bir dönüşüm operatörünü "devre dışı bırakırız".
Böylece f(T&,long)aşırı yük seçilir (ve İntegral Yükselme gerçekleştirilir).
Başka herhangi bir tip için ne olur?
Böylece f(T&,long)aşırı yük seçilir, çünkü tip T*parametreyle eşleşmez .
Not: Borland uyumluluğu ile ilgili dosyadaki açıklamalardan, diziler işaretçilere bozulmaz, ancak referans olarak geçirilir.
Bu aşırı yüklenmede ne olur?
operator&Aşırı yüklenmiş olabileceğinden, türe başvurmaktan kaçınmak istiyoruz .
reinterpret_castBu iş için kullanılabilecek Standart garantiler (@Matteo Italia'nın cevabı: 5.2.10 / 10'a bakınız).
Boost, derleyici uyarılarını önlemek için bazı nitelikler constve volatileniteleyiciler ekler (ve const_castbunları kaldırmak için düzgün bir şekilde a ).
- Dökme
T&içinchar const volatile&
- Şerit
constvevolatile
&Adresi almak için operatörü uygulayın
- Bir
T*
const/ volatileHokkabazlık kara büyü biraz, ama (daha doğrusu 4 aşırı yükleri sağlamak yerine) çalışmalarını kolaylaştırmak yapar. Çünkü o Not Tniteliksiz, biz bir geçirirseniz ghost const&, o zaman T*olduğunu ghost const*böylece eleme gerçekten kayıp edilmemiştir.
EDIT: işaretçi aşırı işlevlerini işaretçi için kullanılır, ben yukarıdaki açıklamayı biraz değiştirdim. Yine de neden gerekli olduğunu hala anlamıyorum .
Aşağıdaki ideone çıktısı bunu bir şekilde özetliyor.