Pembaruan: di C ++ 11, orang dapat menggunakan std::addressof
sebagai ganti boost::addressof
.
Pertama-tama mari kita salin kode dari Boost, minus pekerjaan kompiler di sekitar 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 );
}
Apa yang terjadi jika kita meneruskan referensi ke fungsi ?
Catatan: addressof
tidak dapat digunakan dengan pointer berfungsi
Dalam C ++ jika void func();
dideklarasikan, maka func
adalah referensi ke fungsi tanpa argumen dan tidak mengembalikan hasil. Referensi ke fungsi ini dapat secara sepele dikonversi menjadi pointer ke fungsi - dari @Konstantin
: Menurut 13.3.3.2 keduanya T &
dan T *
tidak dapat dibedakan untuk fungsi. Yang pertama adalah konversi Identity dan yang kedua adalah konversi Function-to-Pointer yang keduanya memiliki peringkat "Pencocokan Tepat" (13.3.3.1.1 tabel 9).
The referensi ke fungsi melewati addr_impl_ref
, ada ambiguitas dalam resolusi yang berlebihan untuk pilihan f
, yang diselesaikan berkat argumen boneka 0
, yang merupakan int
pertama dan bisa dipromosikan ke long
(Konversi Integral).
Jadi kita cukup mengembalikan pointer.
Apa yang terjadi jika kami melewati jenis dengan operator konversi?
Jika operator konversi menghasilkan a T*
maka kami memiliki ambiguitas: untuk f(T&,long)
Promosi Integral diperlukan untuk argumen kedua sedangkan untuk f(T*,int)
operator konversi dipanggil pada yang pertama (terima kasih kepada @litb)
Saat itulah addr_impl_ref
masuk. Standar C ++ mengamanatkan bahwa urutan konversi dapat berisi paling banyak satu konversi yang ditentukan pengguna. Dengan memasukkan jenis addr_impl_ref
dan memaksa penggunaan urutan konversi, kami "menonaktifkan" semua operator konversi yang disertakan.
Dengan demikian f(T&,long)
kelebihan dipilih (dan Promosi Integral dilakukan).
Apa yang terjadi untuk jenis lainnya?
Dengan demikian f(T&,long)
kelebihan dipilih, karena jenisnya tidak sesuai dengan T*
parameter.
Catatan: dari keterangan dalam file tentang kompatibilitas Borland, array tidak membusuk ke pointer, tetapi diteruskan dengan referensi.
Apa yang terjadi pada kelebihan ini?
Kami ingin menghindari penerapan operator&
ke jenis, karena mungkin telah kelebihan beban.
Standar menjamin yang reinterpret_cast
dapat digunakan untuk pekerjaan ini (lihat jawaban @Matteo Italia: 5.2.10 / 10).
Boost menambahkan beberapa fitur const
dan volatile
kualifikasi untuk menghindari peringatan penyusun (dan menggunakan a const_cast
untuk menghapusnya dengan benar).
- Diputar
T&
kechar const volatile&
- Strip
const
danvolatile
- Terapkan
&
operator untuk mengambil alamatnya
- Kembali ke a
T*
The const
/ volatile
juggling adalah sedikit ilmu hitam, tetapi tidak menyederhanakan pekerjaan (daripada memberikan 4 overload). Perhatikan bahwa sejak T
adalah wajar tanpa pengecualian, jika kita lulus ghost const&
, maka T*
adalah ghost const*
, dengan demikian kualifikasi belum benar-benar hilang.
EDIT: pointer overload digunakan untuk fungsi pointer, saya sedikit mengubah penjelasan di atas. Saya masih tidak mengerti mengapa itu perlu .
Output ideone berikut merangkum ini, agak.