Saya ingin tahu cara nullptr
kerjanya. Standar N4659 dan N4849 mengatakan:
- harus memiliki tipe
std::nullptr_t
; - Anda tidak dapat mengambil alamatnya;
- itu dapat langsung dikonversi ke pointer dan pointer ke anggota;
sizeof(std::nullptr_t) == sizeof(void*)
;- konversi menjadi
bool
adalahfalse
; - nilainya dapat dikonversi ke tipe integral secara identik dengan
(void*)0
, tetapi tidak mundur;
Jadi pada dasarnya konstanta dengan makna yang sama (void*)0
, tetapi memiliki tipe yang berbeda. Saya telah menemukan implementasi std::nullptr_t
pada perangkat saya dan itu adalah sebagai berikut.
#ifdef _LIBCPP_HAS_NO_NULLPTR
_LIBCPP_BEGIN_NAMESPACE_STD
struct _LIBCPP_TEMPLATE_VIS nullptr_t
{
void* __lx;
struct __nat {int __for_bool_;};
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR nullptr_t() : __lx(0) {}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR nullptr_t(int __nat::*) : __lx(0) {}
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR operator int __nat::*() const {return 0;}
template <class _Tp>
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
operator _Tp* () const {return 0;}
template <class _Tp, class _Up>
_LIBCPP_INLINE_VISIBILITY
operator _Tp _Up::* () const {return 0;}
friend _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR bool operator==(nullptr_t, nullptr_t) {return true;}
friend _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR bool operator!=(nullptr_t, nullptr_t) {return false;}
};
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR nullptr_t __get_nullptr_t() {return nullptr_t(0);}
#define nullptr _VSTD::__get_nullptr_t()
_LIBCPP_END_NAMESPACE_STD
#else // _LIBCPP_HAS_NO_NULLPTR
namespace std
{
typedef decltype(nullptr) nullptr_t;
}
#endif // _LIBCPP_HAS_NO_NULLPTR
Saya lebih tertarik pada bagian pertama. Tampaknya memuaskan poin 1-5, tapi saya tidak tahu mengapa ia memiliki subclass __nat dan segala sesuatu yang berkaitan dengannya. Saya juga ingin tahu mengapa gagal pada konversi integral.
struct nullptr_t2{
void* __lx;
struct __nat {int __for_bool_;};
constexpr nullptr_t2() : __lx(0) {}
constexpr nullptr_t2(int __nat::*) : __lx(0) {}
constexpr operator int __nat::*() const {return 0;}
template <class _Tp>
constexpr
operator _Tp* () const {return 0;}
template <class _Tp, class _Up>
operator _Tp _Up::* () const {return 0;}
friend constexpr bool operator==(nullptr_t2, nullptr_t2) {return true;}
friend constexpr bool operator!=(nullptr_t2, nullptr_t2) {return false;}
};
inline constexpr nullptr_t2 __get_nullptr_t2() {return nullptr_t2(0);}
#define nullptr2 __get_nullptr_t2()
int main(){
long l = reinterpret_cast<long>(nullptr);
long l2 = reinterpret_cast<long>(nullptr2); // error: invalid type conversion
bool b = nullptr; // warning: implicit conversion
// edditor error: a value of type "std::nullptr_t" cannot be used to initialize an entity of type "bool"
bool b2 = nullptr2;
if (nullptr){}; // warning: implicit conversion
if (nullptr2){};
};
c++
c++17
nullptr
null-pointer
Fullfungo
sumber
sumber
nullptr_t
adalah tipe fundamental. Bagaimanaint
penerapannya?#ifdef _LIBCPP_HAS_NO_NULLPTR
. Ini sepertinya solusi terbaik saat ketika kompiler tidak menyediakannullptr
.nullptr_t
adalah tipe fundamental. Menerapkannya sebagai tipe kelas tidak membuat implementasi yang sesuai. Lihat komentar chris.is_class
danis_null_pointer
keduanya tidak mungkin benar untuk tipe yang sama. Hanya satu dari fungsi kategori tipe primer yang dapat mengembalikan true untuk tipe tertentu.Jawaban:
Ia bekerja dengan cara yang sesederhana mungkin: dengan fiat . Ini bekerja karena standar C ++ mengatakan itu berfungsi, dan bekerja dengan cara itu karena standar C ++ mengatakan bahwa implementasi harus membuatnya bekerja dengan cara itu.
Sangat penting untuk mengenali bahwa tidak mungkin untuk menerapkan
std::nullptr_t
menggunakan aturan bahasa C ++. Konversi dari konstanta null pointerstd::nullptr_t
ke pointer bukan konversi yang ditentukan pengguna. Itu berarti Anda dapat beralih dari konstanta penunjuk nol ke penunjuk, lalu melalui konversi yang ditentukan pengguna ke beberapa jenis lainnya, semuanya dalam satu urutan konversi implisit tunggal.Itu tidak mungkin jika Anda menerapkan
nullptr_t
sebagai kelas. Operator konversi mewakili konversi yang ditentukan pengguna, dan aturan urutan konversi implisit C ++ tidak mengizinkan lebih dari satu konversi yang ditentukan pengguna dalam urutan seperti itu.Jadi kode yang Anda posting adalah perkiraan yang bagus
std::nullptr_t
, tetapi tidak lebih dari itu. Ini bukan implementasi yang sah dari tipe ini. Ini mungkin dari versi kompiler yang lebih lama (dibiarkan karena alasan kompatibilitas belakang) sebelum kompiler memberikan dukungan yang tepat untukstd::nullptr_t
. Anda dapat melihat ini dengan fakta bahwa itu#define
snullptr
, sementara C ++ 11 mengatakan itunullptr
adalah kata kunci , bukan makro.C ++ tidak dapat melaksanakan
std::nullptr_t
, seperti C ++ tidak dapat melaksanakanint
atauvoid*
. Hanya implementasinya yang bisa mengimplementasikan hal-hal itu. Inilah yang membuatnya menjadi "tipe fundamental"; itu bagian dari bahasa .Tidak ada konversi tersirat dari konstanta penunjuk nol ke tipe integral. Ada konversi dari
0
ke tipe integral, tapi itu karena itu adalah nol literer integer, yang merupakan ... integer.nullptr_t
dapat dilemparkan ke tipe integer (viareinterpret_cast
), tetapi hanya dapat secara implisit dikonversi ke pointer dan kebool
.sumber
std::nullptr_t
. Sama seperti Anda tidak dapat menulis jenis yang persis sama dengan perilaku yang diperlukanint
. Anda bisa mendekati, tetapi masih akan ada perbedaan yang signifikan. Dan saya tidak berbicara tentang pendeteksi sifat sepertiis_class
itu memperlihatkan bahwa tipe Anda ditentukan pengguna. Ada beberapa hal tentang perilaku yang diperlukan dari tipe fundamental yang tidak bisa Anda salin dengan menggunakan aturan bahasa.nullptr_t
" Anda berbicara terlalu luas. Dan mengatakan "hanya implementasi yang bisa mengimplementasikannya" hanya membingungkan masalah. Yang Anda maksud adalah itunullptr_t
tidak dapat diimplementasikan " di pustaka C ++ karena itu adalah bagian dari bahasa dasar.std::nullptr_t
diperlukan untuk dilakukan. Sama seperti C ++ bahasa tidak dapat mengimplementasikan tipe yang melakukan semua yangint
harus dilakukan.