Güncelleme: C ++ 11'de std::addressof
bunun 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: addressof
işlev göstermek için bir işaretçi ile kullanılamaz
C ++ ' void func();
da bildirilirse, func
argü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_ref
seçimi için aşırı çözünürlükte bir belirsizlik vardır, f
yapay değişken sayesinde çözülmektedir, 0
bir olduğu, int
birinci 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_ref
zaten 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_cast
Bu 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 const
ve volatile
niteleyiciler ekler (ve const_cast
bunları kaldırmak için düzgün bir şekilde a ).
- Dökme
T&
içinchar const volatile&
- Şerit
const
vevolatile
&
Adresi almak için operatörü uygulayın
- Bir
T*
const
/ volatile
Hokkabazlı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 T
niteliksiz, 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.