Pembaruan: di C ++ 11, orang dapat menggunakan std::addressofsebagai 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: addressoftidak dapat digunakan dengan pointer berfungsi
Dalam C ++ jika void func();dideklarasikan, maka funcadalah 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 intpertama 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_refmasuk. Standar C ++ mengamanatkan bahwa urutan konversi dapat berisi paling banyak satu konversi yang ditentukan pengguna. Dengan memasukkan jenis addr_impl_refdan 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_castdapat digunakan untuk pekerjaan ini (lihat jawaban @Matteo Italia: 5.2.10 / 10).
Boost menambahkan beberapa fitur constdan volatilekualifikasi untuk menghindari peringatan penyusun (dan menggunakan a const_castuntuk menghapusnya dengan benar).
- Diputar
T&kechar const volatile&
- Strip
constdanvolatile
- Terapkan
&operator untuk mengambil alamatnya
- Kembali ke a
T*
The const/ volatilejuggling adalah sedikit ilmu hitam, tetapi tidak menyederhanakan pekerjaan (daripada memberikan 4 overload). Perhatikan bahwa sejak Tadalah 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.