Tôi tò mò muốn biết làm thế nào nullptr
hoạt động. Tiêu chuẩn N4659 và N4849 nói:
- nó phải có loại
std::nullptr_t
; - bạn không thể lấy địa chỉ của nó;
- nó có thể được chuyển đổi trực tiếp thành một con trỏ và con trỏ thành thành viên;
sizeof(std::nullptr_t) == sizeof(void*)
;- chuyển đổi sang
bool
làfalse
; - giá trị của nó có thể được chuyển đổi thành loại tích phân giống hệt
(void*)0
, nhưng không ngược lại;
Vì vậy, về cơ bản nó là một hằng số có cùng ý nghĩa (void*)0
, nhưng nó có một loại khác. Tôi đã tìm thấy việc thực hiện std::nullptr_t
trên thiết bị của mình và nó như sau.
#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
Tôi quan tâm nhiều hơn trong phần đầu tiên mặc dù. Nó dường như thỏa mãn các điểm 1-5, nhưng tôi không biết tại sao nó lại có một lớp con __nat và mọi thứ liên quan đến nó. Tôi cũng muốn biết lý do tại sao nó thất bại trên các chuyển đổi tích hợp.
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){};
};
#ifdef _LIBCPP_HAS_NO_NULLPTR
. Đây có vẻ như là một cách giải quyết nỗ lực tốt nhất khi trình biên dịch không cung cấp nullptr
.
nullptr_t
là một loại cơ bản. Việc thực hiện nó như một kiểu lớp không tạo ra sự thực hiện phù hợp. Xem bình luận của chris.
is_class
và is_null_pointer
cả hai không thể đúng cho cùng một loại. Chỉ một trong các hàm danh mục loại chính có thể trả về true cho một loại cụ thể.
nullptr_t
là một loại cơ bản. Làm thế nào đượcint
thực hiện?